This pipeline was created using the following resources:

Within the RStudio file (.rmd), each code chunk can be executed by clicking the Run button within each chunk or by placing the cursor inside it and pressing Cntrl+Shift+Enter.

After installing R and RStudio, the following Bioconductor R packages are necessary for processing RNASeq raw data, conducting differential expression analysis and data visualization:

For installing packages, execute the code on the Installation section in the corresponding Bioconductor page.

For instance, for installing DESeq2:

if (!require("BiocManager", quietly = TRUE))
    install.packages("BiocManager")
BiocManager::install("DESeq2")

The remaining packages are part of the Comprehensive R Archive Network (CRAN), which is the official R packages repository. These can be installed in RStudio by going to ToolsInstall Packages and in the Install from option select Repository (CRAN), followed by specifying the intended packages:


After installing every required package, these libraries should be loaded into RStudio so that their commands and functions are available to use. To do so, enter:

#Loading libraries
library("DESeq2")
library("edgeR")
library("AnnotationDbi")
library("org.Hs.eg.db")
library("ggplot2")
library("ggalt")
library("ggrepel")
library("textshaping")
library("tidyverse")
library("RColorBrewer")
library("circlize")
library("pheatmap")
library("ComplexHeatmap")
library("EnhancedVolcano")

Note: Libraries should always be re-loaded when re-opening the script.

Afterwards, open the raw count data file in RStudio. This file is a table that results from mapping the sequencing reads to a reference genome and displays the number of reads assigned to each gene, in each sample. This tab-delimited file contains a header row with each sample name and each row name represents a unique Ensembl gene ID (ENSG).

In this work, the file “2D_counts.txt” was used for differential gene expression analysis of 2D Native hASCs vs 2D Glycoengineered hASCs. For assessing the impact of cell-cell tethering in the transcriptome, 2D Glycoengineered hASCs vs 3D Cellgels samples were pooled into “2Dv3D_counts.txt”.


For ease of comprehension, each function is described line-by-line in commented descriptions. For further information, please refer to each package’s vignette containing the comprehensive command list.


First, RNASeq analysis in 2D conditions was conducted:

#Reads count table and assigns it to a variable called "Counts".
Counts <- read.table("2D_counts.txt", header = TRUE, row.names = 1, sep ="\t")
Counts

Note: Before starting the analysis, confirm that the raw counts table contains the actual unprocessed reads and not the output of a previous DESeq2 workflow. Raw count values are stored as integers, whereas normalized counts are decimals numbers. DESeq2 differential expression analysis can only be conducted on raw unprocessed counts.

#Creates data frame called "coldata" that assigns experimental conditions ("2DControl" or "2DGly") to each sample and stores this factor in the "treatment" column. Also renames the original sample names in the .bam file to shorter and convenient IDs.
coldata <- DataFrame(id = c("2DC1", "2DC2", "2DC3", "2DC4", "2DC5", "2DG1", "2DG2", "2DG3", "2DG4", "2DG5"), treatment= factor(c(rep("2DControl", times = 5), rep("2DGly", times = 5)), levels = c("2DControl", "2DGly")))

#Saves the formatted counts table to a .txt file.
write.table(Counts, file = "2D_counts_v2.txt", sep = "\t", quote=FALSE, col.names = TRUE)
coldata
DataFrame with 10 rows and 2 columns
            id treatment
   <character>  <factor>
1         2DC1 2DControl
2         2DC2 2DControl
3         2DC3 2DControl
4         2DC4 2DControl
5         2DC5 2DControl
6         2DG1 2DGly    
7         2DG2 2DGly    
8         2DG3 2DGly    
9         2DG4 2DGly    
10        2DG5 2DGly    


Next, a pre-filtering strategy is applied to the Counts table. Before proceeding with differential expression analysis, it is important to filter out genes that consistently present extremely low expression. This reduces multiple testing burden and helps in increasing the statistical power of the analysis, while keeping genes of interest.

Herein, counts per million (CPM) are used for pre-filtering rather than raw counts, as CPM accounts for differences in library sizes (i.e., sequencing depth = total number of counts) across samples, ensuring a more robust comparison. For instance, if samples yielded uneven library sizes (e.g. 15 M vs 40 M), a filtering criteria solely based on raw counts would not avoid favoring genes that are expressed in the larger library. CPM is calculated through edgeR as the raw counts divided by library size and multiplied by one million.

Note: CPM calculation through edgeR package is more sophisticated than manually applying the formula as it also automatically corrects for library composition using calcNormFactors.

As a rule of thumb, for library sizes of about 20 M reads, a CPM = 0.5 is used as it corresponds to a raw count of 10 - 15.

Note: To view the library size for each sample enter:

library_size <- colSums(Counts)
library_size.df <- as.data.frame(library_size)
rownames(library_size.df) <- coldata$id
library_size.df
#Cross-checking whether a CPM threshold of 0.5 corresponds to approximately 10 - 15 counts in these samples.
myCPM_colnames = c("C1", "C2", "C3", "C4", "C5", "G1", "G2", "G3", "G4", "G5")
myCPM <- cpm(Counts) #edgeR calculates the Counts Per Million (CPM) values for the Raw Counts object.
plot(myCPM[,1], Counts[,1], xlab="CPM", ylab="Raw Counts", main=paste("Sample", myCPM_colnames[1]), 
     ylim=c(0,50), xlim=c(0,3))
#Adds reference lines at x = 0.5 CPM and y = 10 Raw Counts
abline(v=0.5) + abline(h=10)

Considering library sizes in this dataset are on the order of 20 M, a threshold for genes with CPM > 0.5 was established. An additional requirement for expression in 3 or more libraries is used, as each group contains 5 replicates. Applying a stringent pre-filtering threshold ensures a more reliable and robust analysis. This criteria eliminates genes that are unlikely to be relevant due to (i) inconsistent reads across different samples, and (ii) increased fold change and variance associated with extremely low counts. In addition, this setup ensures that a gene will be retained even if it is only expressed in one experimental condition.

#Pre-filtering Counts to CPM > 0.5 in at least 3 different samples
keepCPM <- rowSums(cpm(Counts) > 0.5) >= 3
CPMCounts <- Counts[keepCPM,]
nrow(Counts)    #61552 = Total number of mapped genes
nrow(CPMCounts) #14194 = Number of genes after pre-filtering
#Running DESeq2 analysis
ddsCPM <- DESeqDataSetFromMatrix(countData = CPMCounts, colData = coldata, design = ~treatment)
ddsCPM <- DESeq(ddsCPM)
resddsCPM <- results(ddsCPM)
resddsCPM #Show DESeq2 results table
log2 fold change (MLE): treatment 2DGly vs 2DControl 
Wald test p-value: treatment 2DGly vs 2DControl 
DataFrame with 14194 rows and 6 columns
                 baseMean log2FoldChange     lfcSE      stat    pvalue      padj
                <numeric>      <numeric> <numeric> <numeric> <numeric> <numeric>
ENSG00000160072  217.7990      0.2211119  0.138383  1.597820 0.1100829 0.2225651
ENSG00000142611   66.1508     -0.4467950  0.178257 -2.506466 0.0121945 0.0393714
ENSG00000225630  525.1312      0.0389046  0.147856  0.263125 0.7924545 0.8773250
ENSG00000131584   42.3183      0.4723784  0.288730  1.636059 0.1018273 0.2098193
ENSG00000169972  130.7999      0.0926638  0.124668  0.743283 0.4573102 0.6180456
...                   ...            ...       ...       ...       ...       ...
ENSG00000210196   52.4841     -0.1962727  0.203209 -0.965866  0.334111  0.499162
ENSG00000276256   89.2431      0.1866894  0.135644  1.376321  0.168722  0.306774
ENSG00000273748   44.4494      0.1237211  0.194458  0.636234  0.524624  0.677302
ENSG00000276197   12.6270      0.0673584  0.571645  0.117833  0.906200  0.946688
ENSG00000271254   50.1216     -0.1487663  0.201549 -0.738116  0.460444  0.620557
#Output DESeq2 Normalized Counts - Necessary for submitting RNASeq datasets to the SRA repository.
normalized_counts <- counts(ddsCPM, normalized=TRUE)
write.table(normalized_counts, file = "2D_normalizedcounts.txt", sep = "\t", quote=FALSE, col.names = TRUE)


Next, to improve interpretability, it is useful to convert the mapped ENSEMBL IDs (e.g., ENSG00000115414) to the more recognizable Gene Symbols (e.g., FN1 for the Fibronectin gene).

#Adds a new column "geneID" to the results table containing the corresponding Gene Symbols to each row
GeneIDs <- mapIds(org.Hs.eg.db,
              keys = row.names(resddsCPM),
              keytype = "ENSEMBL",
              column = "SYMBOL")
ENS_geneIDs <- stack(GeneIDs)
resddsCPM$geneID <- ENS_geneIDs$values
resddsCPM #Show the updated DESeq2 results table with the new geneID column
log2 fold change (MLE): treatment 2DGly vs 2DControl 
Wald test p-value: treatment 2DGly vs 2DControl 
DataFrame with 14194 rows and 7 columns
                 baseMean log2FoldChange     lfcSE      stat    pvalue      padj       geneID
                <numeric>      <numeric> <numeric> <numeric> <numeric> <numeric>  <character>
ENSG00000160072  217.7990      0.2211119  0.138383  1.597820 0.1100829 0.2225651       ATAD3B
ENSG00000142611   66.1508     -0.4467950  0.178257 -2.506466 0.0121945 0.0393714       PRDM16
ENSG00000225630  525.1312      0.0389046  0.147856  0.263125 0.7924545 0.8773250     MTND2P28
ENSG00000131584   42.3183      0.4723784  0.288730  1.636059 0.1018273 0.2098193        ACAP3
ENSG00000169972  130.7999      0.0926638  0.124668  0.743283 0.4573102 0.6180456        PUSL1
...                   ...            ...       ...       ...       ...       ...          ...
ENSG00000210196   52.4841     -0.1962727  0.203209 -0.965866  0.334111  0.499162           NA
ENSG00000276256   89.2431      0.1866894  0.135644  1.376321  0.168722  0.306774    LOC389831
ENSG00000273748   44.4494      0.1237211  0.194458  0.636234  0.524624  0.677302           NA
ENSG00000276197   12.6270      0.0673584  0.571645  0.117833  0.906200  0.946688           NA
ENSG00000271254   50.1216     -0.1487663  0.201549 -0.738116  0.460444  0.620557 LOC102724250

Note: Gene symbols (‘geneID’ column) with NA values are typically pseudogenes, some of those associated with producing antisense RNA transcripts. Not every ENSEMBL Gene ID corresponds to a HGNC Gene Symbol entry.

#Output full results: Normalized counts + DESeq2 results table
results_sum <- cbind(normalized_counts, resddsCPM)
#write.csv(results_sum, file = "2D_full_results.csv", quote=FALSE, col.names = TRUE) #.CSV alternative to upload data
write.table(results_sum, file = "2D_full_results.txt", sep = "\t", quote=FALSE, col.names = TRUE) #.TXT for better data fetching


After DESeq2 processing, differential expression analysis of genes can be conducted. In this work, genes are considered to be Differentially Expressed Genes (DEGs) if they exhibit an adjusted p-value < 0.05 (padj, Benjamini-Hochberg procedure for multiple testing correction) and present log2(fold change) > 1 or < -1.

Specifically, a log2(fold change) > 1 translates into an > 2-fold upregulated gene expression, whereas a log2(fold change) < -1 indicates a < 0.5 fold downregulation. By combining both of these thresholds, this robust criteria provides greater specificity for identifying genes that are not only statistically significant, but are also more likely to be biologically relevant.

#Analysis of DEGs distribution for Donut Plot

resddsCPM <- resddsCPM[!is.na(resddsCPM$padj), ] #Clean-up of genes containing 'NA' in 'padj' column. This occurs in genes filtered out by DESeq2 through automatic independent filtering or containing a sample with an extreme count outlier, as detected by Cook's distance.

sigs <- resddsCPM[resddsCPM$padj < 0.05,]       #Creates a subset of genes that meet the padj < 0.05 threshold.
sigsALL <- sigs[abs(sigs$log2FoldChange) > 1,]  #Total DEGs, use of absolute log2fold change values ('abs').
sigsUP <- sigs[sigs$log2FoldChange > 1,]        #Upregulated DEGs.
sigsDOWN <- sigs[sigs$log2FoldChange < -1,]     #Downregulated DEGs.

#Summary
#dim(resddsCPM) #Total genes = 14193
#dim(sigs)      #Total statistically significant genes = 4692
#dim(sigsALL)   #Total DEGs = 568
#dim(sigsUP)    #Upregulated DEGs = 180
#dim(sigsDOWN)  #Downregulated DEGs = 388

#Output DEGs
sigsALL.df <- as.data.frame(sigsALL)
sigsALL.df$symbol <- mapIds(org.Hs.eg.db, keys = rownames(sigsALL.df), keytype = "ENSEMBL", column = "SYMBOL") #Alternative way to add Gene Symbols to each row, available upon conversion to a data.frame object.
write.csv(sigsALL.df, "2D_DEGs.csv", quote = FALSE, col.names = TRUE)

#Output Volcano table
write.csv(resddsCPM, "2D_Volcano.csv", quote = FALSE, col.names = TRUE)


Next, the quality of the RNASeq dataset can be validated by plotting the per-gene dispersion estimates versus the mean expression. The visualization of this plot (plotDispEsts) allows for rapidly checking whether the fitted mean-dispersion relationship (red trend line) shows an appropriate fit to the data and ensure the validity of differential testing assumptions in downstream analysis.

#Plot fitted mean-dispersion relationship
plotDispEsts(ddsCPM)


In addition, it is important to perform a scatterplot of the biological coefficient of variation (BCV) against the average abundance of each gene. A BCV plot provides further visualization of the biological variability across samples in terms of gene expression, and whether this variance is adequate for fitting.

As found below, the common dispersion (Disp) is 0.01331 and the BCV (square root of Disp) is 0.1154. Typically, the asymptotic value for BCV tends to be within the 0.05 - 0.2 range for cell line experiments or genetically identical mice, whereas larger values (> 0.3) can be found in human subjects datasets. As a result, this BCV analysis further confirms the validity of the dataset for subsequent downstream analysis, as it will be demonstrated below.

#edgeR processing for fitting and calculations
condition = factor(c(rep("2DControl", times = 5), rep("2DGly", times = 5)))
dgeGlm <- DGEList(counts = CPMCounts, group = condition)
str(dgeGlm)
names(dgeGlm)
dgeGlm[["samples"]]
#Calculate common dispersion (Disp) and biological coefficient of variation (BCV)
design <- model.matrix(~condition)
dgeGlmComDisp <- estimateGLMCommonDisp(dgeGlm, design, verbose = TRUE) #Disp = 0.01331, BCV = 0.1154
Disp = 0.01331 , BCV = 0.1154 
#Plotting BCV scatterplot
dgeGlmTrendDisp <- estimateGLMTrendedDisp(dgeGlmComDisp, design)
dgeGlmTagDisp <- estimateGLMTagwiseDisp(dgeGlmTrendDisp, design)
plotBCV(dgeGlmTagDisp)


RNASeq datasets often contain thousands of genes across multiple samples, making it extremely complex to detect and analyze patterns of gene expression data. In this context, Principal Component Analysis (PCA) transforms data into a set of uncorrelated variables (i.e., principal components), which is useful for reducing data dimensionality, providing a blind and unbiased assessment of gene expression patterns across multiple samples and conditions. PC1 describes the most variation within the data, PC2 the second most, and so forth.

Therefore, PCA is highly valuable for (i) identifying gene expression trends (e.g., confirming the biological relevance of the treatment/disease or experimental condition), (ii) identifying clusters of samples and their relationships, and (iii) screening out any potential outliers or batch effects. Visualizing these effects assists in confirming the hypothesis tested in further DEGs downstream analysis.

To create a PCA plot, first a vst() (i.e., variance-stabilizing transformation) function should be applied to remove the dependence of the variance on the mean. This is because analysis of multi-dimensional data (such as PCA) works best for homoskedastic data (i.e., consistent variability), whereas in RNASeq data variance increases with the mean values. Unlike the other DESeq2 function (i.e., rlog()) function for this purpose, vst() is more sensitive to size factor and also normalizes with respect to library size.

#Output 2D PCA Plot
vsdata <- vst(ddsCPM, blind = FALSE) #Apply variance-stabilizing transformation to DESeq object 'ddsCPM'
#By default both these functions are **blind** to the sample design formula given to DESeq2 in DESeqDataSetFromMatrix(), however this is not appropriate if one expects large differences in counts explained by differences in experimental design. In such cases, the blind parameter should be set to 'FALSE' as recommended in DESeq2 vignette. 


#plotPCA(vsdata, intgroup = "treatment")          #Preview PC1 and PC2 % for correct axis labeling.
PCAraw <- plotPCA(vsdata, intgroup = "treatment") #Create a PCA plot using 'vsdata' and groups it by 'treatment'.
group.colors <- c("#619CFF","#00C19F")            #Vector containing color codes to be used in each group.
new_pca <- ggplot(PCAraw[["data"]],               #Create a ggplot using 'data' data.frame within 'PCAraw' object. 
  aes(PC1, PC2, color=group)) +                   #Construct aesthetic mapping using PC1 and PC2.
  scale_color_manual(values = group.colors) +     #Specify a vector of colors.
  geom_point(size = 2.5) +                        #Change marker size.
  xlab("PC1 (79%)") +                             #Text used for X axis.
  ylab("PC2 (9%)") +                              #Text used for Y axis.
  ylim(-10, 10) +                                 #Lower/upper limits for Y axis.
  xlim(-12, 12) +                                 #Lower/upper limits for X axis.
  theme_grey() +                                  #Set a grey background with white gridlines.
theme(axis.title.x = element_text(size = 14),     #Customize size and style of axis titles and text.
  axis.title.y = element_text(size = 14),
  axis.text.x = element_text(size = 12, face = "bold"),
  axis.text.y = element_text(size = 12, face = "bold"))

new_pca
ggsave("2D_PCA.svg", new_pca, dpi = 600, width = 2.6, height = 2, units = "in", scale = 2) #Exports plot in .svg


Apart from PCA, another important analysis to perform is to determine whether intergroup variability - which represents differences between experimental conditions in comparison with control conditions - is greater than the intragroup variability, representing technical or biological variance. This is achieved by calculating distance as represented by correlation across samples, typically using the Pearson’s correlation plot.

Pearson’s coefficient reflects the linear relationship between 2 variables accounting for differences in mean and standard deviation. For instance, the more similar the gene expression profiles for all transcripts are between two samples, the higher the correlation coefficient will be. These coefficients are calculated between all samples and are then visualized as a heatmap.

Similar to PCA, the Pearson’s correlation plot provides an overview of the overall strength of the biological effect of the experiment, assessing whether replicates and different conditions group together, as well as identify outliers that were not excluded during upstream steps (e.g., sample labeling or genomic alignment).

#Output 2D Pearson's Correlation Plot
vsdata <- vst(ddsCPM, blind = FALSE)                    #Apply variance-stabilizing transformation.
sampleDists <- cor(method = "pearson", assay(vsdata))   #Calculate Pearson correlation coefficients.
sampleDistMatrix <- as.matrix(sampleDists)              #Convert to matrix format.
rownames(sampleDistMatrix) <- paste(vsdata$id)          #Label Sample names.
colnames(sampleDistMatrix) <- paste(vsdata$id)          #Label Sample names.
colors <- colorRampPalette(brewer.pal(9, "Blues"))(255) #Color palette range for heatmap visualization.
SampleDistance = pheatmap(sampleDistMatrix, col=colors) #Generate heatmap with 'sampleDistMatrix' and 'colors' inputs.
SampleDistance #ggsave("SD_2D_Pearson.svg", SampleDistance, dpi = 600, width = 2.55, height = 2, units = "in", scale = 2) 

#Alternative: Euclidean Distances Correlation Plot, as described in DESeq2 vignette
sampleDists_Euclidean <- dist(t(assay(vsdata)))                 #Calculate Pearson correlation coefficients.
sampleDistMatrix_Euclidean <- as.matrix(sampleDists_Euclidean)  #Convert to matrix format.
rownames(sampleDistMatrix_Euclidean) <- paste(vsdata$id)        #Label Sample names.
colnames(sampleDistMatrix_Euclidean) <- paste(vsdata$id)        #Label Sample names.
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")))(255)    #Color palette range for heatmap visualization.
SampleDistancevignette = pheatmap(sampleDistMatrix_Euclidean,   #Generate heatmap with 'sampleDistMatrix' and 'colors' inputs.
         clustering_distance_rows=sampleDists_Euclidean,        #Clustering by Euclidean distance.
         clustering_distance_cols=sampleDists_Euclidean,        #Clustering by Euclidean distance.
         col=colors)
SampleDistancevignette #ggsave("2D_SD.svg", SampleDistancevignette, dpi = 600, width = 2.55, height = 2, units = "in", scale = 2)



Next, a Volcano plot can be assembled to provide a general overview of the gene expression profiles of 2D Native hASCs vs 2D Glycoengineered hASCs. Volcano plots provide a clear and intuitive visualization of statistical significance and the extent of fold changes for every gene detected. Here, each gene is plotted with their statistical significance (adjusted p-values on the y-axis) agaisnt the fold change (log2 fold change on the x-axis).

Then, a threshold is set to highlight genes that are differentially expressed (DEGs), as represented in the plot in the form of dashed lines. As aforementioned, this work considers as DEGs genes that present an adjusted p-value < 0.05 and log2(fold change) > 1 or < -1. This combination of significance and fold change information allows researchers to efficiently identify and prioritize genes of interest for further investigation. In addition, Volcano plots can also assist in screening out genes with high statistical significance but low fold changes, which may be significant due to large sample sizes but may not have substantial biological relevance.

#Output 2D Volcano plot with specific Genes of Interest labelled

resddsCPM.df <- as.data.frame(resddsCPM)                        #Convert DESeq2 results object to a data frame.

#Create custom key-value pairs for 'Up', 'Down', 'Non-DEG' expression. Achieved using nested 'ifelse' statements.
keyvals <-  ifelse(resddsCPM$padj > 0.05, 'grey30',             #If padj > 0.05 assign grey color.
            ifelse(resddsCPM$log2FoldChange < -1, 'royalblue',  #If log2foldchange < -1, assign blue color.
            ifelse(resddsCPM$log2FoldChange > 1, 'firebrick3',  #If log2foldchange > 1, assign red color.
                                                  'grey30')))   #Other values assigned grey color.
#Rename elements in 'keyvals' vector:
names(keyvals)[keyvals == 'firebrick3'] <- 'Up'                 #Assign 'Up' to elements in red.
names(keyvals)[keyvals == 'grey30'] <- 'Non-DEG'                #Assign 'Non-DEG' to elements in red.
names(keyvals)[keyvals == 'royalblue'] <- 'Down'                #Assign 'Up' to elements in red.

#Define vector containing Gene Symbols to highlight in plot
selected = c("PTGS2", "KRT19", "CXCL1", "SLC7A11", "NDNF", "PGD", "VCAM1", "GPC1", "ANGPT1", "GDF15")

#Volcano plot settings
enhvolc <- EnhancedVolcano(resddsCPM.df,                        #Create Volcano plot using 'resddsCPM.df'
        x = "log2FoldChange",                                   #Column name containing log2(fold change) values.
        y = "padj",                                             #Column name containing adjusted p-value values.
        #lab = NA,                                              #Uncomment this function for unlabeled genes.
        pCutoff = 0.05,                                         #Cut-off threshold for statistical significance.
        FCcutoff = 1,                                           #Cut-off threshold for absolute log2(fold change).
        title = NULL,                                           #Plot title.
        subtitle = NULL,                                        #Plot subtitle.
        caption = NULL,                                         #Plot caption.
        xlab = bquote(~Log[2]~"(Fold Change)"),                 #Label for x-axis. 
        ylab = bquote(~-Log[10] ~ "(" * italic(P[adj]) * ")"),  #Label for y-axis.
        colAlpha = 0.5,                                         #Alpha for color transparency.
        colCustom = keyvals,                                    #Override color scheme (e.g. color by pathway, cell-type or condition).
        pointSize = 1,                                          #Size of plotted points.
        labSize = 4,                                            #Size of labels for each point.
        drawConnectors = TRUE,                                  #Connect labels to each corresponding point by line connectors.
        widthConnectors = 0.65,                                 #Line width of connectors.
        arrowheads = FALSE,                                     #Draw arrowheads instead of simple line connectors.
        boxedLabels = TRUE,                                     #Draw labels within boxes.
        directionConnectors = 'both',                           #Direction to draw connectors (e.g., 'y', 'x' or 'both').
        xlim = c(-6, 6),                                        #Limits of x-axis.
        ylim = c(0, -log10(10e-255)),                           #Limits of y-axis.
#Exclude these if not highlighting specific genes
        lab = resddsCPM.df$geneID,                              #Input Gene Symbol column of data.frame object.
        selectLab = selected                                    #Vector containing a subset of genes of interest.
        )

#Customize axis limits and breaks
p1 <-  enhvolc +
    ggplot2::coord_cartesian(xlim = c(-6.4, 6.4),               #Zoom plot to the specific x-axis limit. 
                             ylim = c(0, 250)) +                #Zoom plot to the specific y-axis limit. 
    ggplot2::scale_x_continuous(breaks=seq(-6, 6, 2)) +         #Set spacing of breaks in plot x-axis.
    ggplot2::scale_y_continuous(breaks=seq(0, 250, 50))         #Set spacing of breaks in plot y-axis.
p1
ggsave("2D_Volcano_Wide_Label.svg", p1, width = 4.5, height = 2.8, units = "in", scale = 2)


Alternatively, Volcano plots can be customized via other packages (e.g., ‘ggplot2’) as subplot overlays for presenting a list of target genes with different shading specifications.

For instance, overlaying all genes that match a specific requirement (i.e., all ILs genes).


In addition, it is also possible to assemble a Volcano plot containing an overlay of genes of interest on top.


Alternatively, it is possible to assemble a MA plot, which conveys a similar overview to Volcano plots. However, this plot lacks the design flexibility that Volcano plots offer through their dedicated R packages.

#Alternative to Volcano - MA Plot. Less flexibility in customizing the final figure.
MAPlot_dds <- DESeq2::plotMA(resddsCPM, alpha = 0.05, #Set p-value cut-off threshold.
               colNonSig = "gray30",                  #Set color code for Non-DEG.
               colSig = "royalblue3",                 #Set color code for statistically significant.
               ylim = c(-7, 7))                       #Set y-axis limit.
abline(h = c(1, -1), lty = 2)                         #Draw horizontal lines at the specified y-axis values, line type - dashed.


Apart from Volcano plots, Heatmaps provide an important visualization tool in RNASeq for detecting gene expression trends and highlighting genes with relevant biological functions. Herein, each sample is assigned to a column, and each row corresponds to a DEG with color-coded expression level. Expression values are typically normalized and transformed (i.e., row z-scaling) to ensure that genes with varying expression levels can be compared easily. Heatmaps are usually paired with hierarchical clustering algorithms (e.g., Pearson’s) that group together genes and samples with similar expression profiles, generating a hierarchical tree-like dendrogram. Heatmaps are thus useful in RNASeq downstream analysis for revealing co-expression patterns and biological functions affected by experimental conditions.

#Transformation of data for Heatmap
vsdata <- vst(ddsCPM, blind = FALSE)        #Apply variance-stabilizing transformation.
vst_mat <- assay(vsdata)                    #Create matrix with transformed gene expression values.
vst_mat <- vst_mat[rownames(sigsALL.df), ]  #Subset matrix to include only DEGS, i.e., rows that match genes listed in 'sigsALL.df'.
Genename <- mapIds(org.Hs.eg.db,            #Map Ensembl ID from matrix to Gene Symbol and store in variable 'Genename'.
               keys = row.names(vst_mat),
              keytype = "ENSEMBL",
              column = "SYMBOL")

#Replace NA gene symbols with ENSEMBL IDs in vst_mat.
#(i) Identify which entries in 'Genename' have missing values (NA).
no_symbol_idx <- is.na(Genename)

#(ii) For 'Genename' entries with NA, replace values with original Ensembl ID extracted from 'vst_mat' row names.
Genename[no_symbol_idx] <- row.names(vst_mat)[no_symbol_idx]

#(iii) Convert 'Genename' vector into a single column data.frame, making it suitable for assignment to row names of 'vst_mat'
ENS_geneIDs <- stack(Genename)       

#(iv) Replace Ensembl ID entries with Gene Symbols when available, and retains original Ensembl ID if NA.
row.names(vst_mat) <- ENS_geneIDs$values                      


#Double-check that no DEGs were lost during assignment
#dim(vst_mat) #568 DEGs -> TRUE

#Scale genes z-score by row, as otherwise large values from highly expressed genes would dominate the plot
vst_mat_z <- t(scale(t(vst_mat)))

#Assign column names to each sample
colnames(vst_mat_z) <- c("2DC1", "2DC2", "2DC3", "2DC4", "2DC5", "2DG1", "2DG2", "2DG3", "2DG4", "2DG5")

#Heatmap parameters
col_fun <- colorRamp2(c(-2, 0, 2),                        #Create segments for the color gradient.
                c("#2166AC", "white", "#B2182B"))   #Create color gradient with the specified color codes.

lgd_list <- list(title = "Z-score",                       #Set legend title.
                legend_height = unit(2.5, "cm"),          #Set height of the legend body.
                grid_width = unit(0.4, "cm"),             #Set width of each legend grid.
                title_position = "topcenter",             #Set position of the title.
                gap = unit(4, "mm"))                      #Set gap between heatmap and legend.
#Output full DEGs Heatmap
ht <- Heatmap(vst_mat_z,                                        #Matrix input for heatmap.
        col = col_fun,                                          #Set vector of colors for interpolation.
        show_column_names = FALSE,                              #Whether to show column labeling. 
        show_row_names = FALSE,                                 #Whether to show row labeling.
        #row_labels = sigs.df[rownames(vst_mat_z),]$Symbol,     #Uncomment to specify row labeling. 
        row_names_gp = gpar(fontsize = 5),                      #Set font size for row labeling.
        clustering_distance_columns = "pearson",                #Set clustering method for column dendrogram.
        clustering_distance_rows = "pearson",                   #Set clustering method for row dendrogram.
        #column_labels = colnames(vst_mat_z),                   #Uncomment for specifying column labeling. 
        column_names_gp = gpar(fontsize = 5),                   #Set font size for column labeling.
        row_dend_reorder = FALSE,                               #Whether to apply row dendrogram reordering. 
        column_dend_reorder = TRUE,                             #Whether to apply column dendrogram reordering. 
        show_row_dend = TRUE,                                   #Whether to show row dendrogram clustering.
        row_dend_width = unit(10, "mm"),                        #Set width of row dendrograms.
        show_column_dend = FALSE,                               #Whether to show column dendrogram clustering.
        width = unit(2, "in"),                                  #Set heatmap width.
        height = unit(10, "in"),                                #Set heatmap height.
        name = "Z-score")                                       #Set title.
#ht
#tiff("2D_Full_Heatmap.tiff", width = 4, height = 10, units = "in", res=600)
#draw(ht)
#dev.off()



Next, it becomes highly valuable to zoom in on specific gene subsets that are involved in relevant biological processes. Herein, DEGs related to extracellular matrix organization, glycoproteins and secreted factors are mapped to unveil the impact of the cell surface engineering process on the transcriptome.

#Create vectors of gene lists
Genelist_ECM = c("ADAMTS15", "WNT16", "WNT2", "WNT9A", "ANGPTL4", "BMP4", "MMRN2", "COL21A1", "COL22A1", "OMD", "TNXB", "THSD4")
Genelist_Glycoproteins = c("ADAMTS15", "APCDD1L", "ABCA6", "ABCA8", "ABCA9", "ABCB6", "ABCC2", "ABCC3", "ATP6V0E2", "BRINP1", "CEBPB", "CD200", "EPHA5", "FAM20A", "GPR137B", "GPR68", "GPRC5A", "GPRC5B", "KCNJ5-AS1", "KITLG", "KIT", "LIF", "LYPD1", "MPL", "NOX4", "SHANK2", "SLITRK4", "ST6GALNAC5", "ST6GAL2", "B3GNT8", "WNT16", "WNT2", "WNT9A", "ADCY4", "AFP", "MGAT4B", "AREG", "ANGPT1", "ANGPTL4", "AGTR1", "AQP1", "ACKR3", "B3GALT2", "B4GALNT1", "BMP4", "CDH18", "CDH6", "CDH8", "CHST6", "CDON", "CEMIP", "CHRM2", "CSGALNACT1", "COL21A1", "COL22A1", "C1RL", "CFHR1", "CNNM4", "ENPP4", "ELAPOR1", "ESM1", "EDNRB", "EFNA5", "EPOR", "GRPR", "GPC1", "GDF15", "GDF6", "HHIP", "HGF", "HMMR", "HSD11B1", "IGSF10", "IGFBP3", "ICAM1", "IFNE", "IL1RL1", "IL20RA", "IL34", "JUP", "LRRN3", "LIPG", "ME1", "MXRA5", "MMRN2", "NDNF", "NETO2", "NOTCH4", "OMD", "PLAT", "PDGFRL", "PLXDC1", "GALNT15", "GALNT3", "POPDC3", "KCNK1", "PCSK6", "PCSK9", "PTGDR", "PTGER3", "PTGS2", "PTPRQ", "PCDHB5", "RAET1E", "RNF128", "RNF150", "SPP1", "SEMA3C", "SEMA3D", "SEMA6D", "PRSS35", "SNAI1", "SLC1A2", "SLC12A9", "SLC14A1", "SLC2A12", "SLC2A5", "SLC24A3", "SLC38A1", "SLC38A4", "SLC4A8", "SLC7A11", "SLC7A14", "TNXB", "TENM4", "THBD", "TRPC6", "TMEM130", "VCAM1")
Genelist_Secreted = c("ADAMTS15", "ABCB6", "CCL26", "CXCL1", "CXCL2", "CXCL3", "CXCL6", "CXCL8", "C1QTNF2", "FAM20A", "HTRA3", "KCNJ5-AS1", "KITLG", "LIF", "WNT16", "WNT2", "WNT9A", "AKR1B10", "AFP", "ANGPT1", "ANGPTL4", "BMP4", "CEMIP", "COL21A1", "COL22A1", "C1RL", "CFHR1", "ESM1", "EDN1", "EPOR", "FABP5", "GPC1", "GDF15", "GDF6", "HHIP", "IGSF10", "IGFBP3", "IFNE", "IL1B", "IL1RL1", "IL34", "LIPG", "MXRA5", "MMRN2", "NDNF", "OMD", "PINLYP", "PLAT", "PDGFRL", "PLXDC1", "PCSK6", "PCSK9", "RAET1E", "SPP1", "SCG5", "SEMA3C", "SEMA3D", "PRSS35", "TNXB", "THSD4")

#Replace here [Genelist_ECM] with the name of the vector for specific genes c("XX", "XY", "XZ")
selected_DEGs <- Genelist_Secreted

#Filters the matrix to retain only the rows that correspond to the genes listed in 'selected_DEGs' vector.
vst_matSelected <- vst_mat[rownames(vst_mat) %in% selected_DEGs, ]

#Double check to ensure that all selected DEGs were retrieved
#dim(vst_mat)                    #568 DEGs
#dim(vst_matSelected)            #60 DEGs
#length(Genelist_Secreted)       #60 DEGs

#Apply row z-scaling
vst_matSelected_z <- t(scale(t(vst_matSelected)))

#Assign column names to each sample
colnames(vst_matSelected_z) <- c("2DC1", "2DC2", "2DC3", "2DC4", "2DC5", "2DG1", "2DG2", "2DG3", "2DG4", "2DG5")

#Heatmap parameters
col_fun <- colorRamp2(c(-2, 0, 2),                        #Create segments for the color gradient.
                      c("#2166AC", "white", "#B2182B"))   #Create color gradient with the specified color codes.

lgd_list <- list(title = "Z-score",                       #Set legend title.
                title_gp = gpar(fontsize = 12),           #Set font size for legend title.
                legend_height = unit(2.5, "cm"),          #Set height of the legend body.
                legend_width = unit(5, "cm"),             #Set width of the legend body.
                grid_width = unit(0.4, "cm"),             #Set width of each legend grid.
                direction = "horizontal",                 #Whether scale is 'horizontal' or 'vertical'
                title_position = "topcenter",             #Set position of the title.
                gap = unit(4, "mm"))                      #Set gap between heatmap and legend.


ht_selected <- Heatmap(vst_matSelected_z,                 #Matrix input for heatmap.
        col = col_fun,                                    #Vector of colors for interpolation.
        rect_gp = gpar(col = "grey30", lwd = 0.15),       #Border line color and width of each cell.
        show_column_names = FALSE,                        #Whether to show column labeling.
        show_row_names = TRUE,                            #Whether to show row labeling.
        row_names_gp = gpar(fontsize = 5),                #Set font size for row labeling.
        clustering_distance_columns = "pearson",          #Set clustering method for column dendrogram.
        clustering_distance_rows = "pearson",             #Set clustering method for row dendrogram.
        #column_labels = colnames(vst_matSelected_z),     #Uncomment to specify column labeling.
        column_names_gp = gpar(fontsize = 5),             #Set font size for column labeling.
        row_dend_reorder = FALSE,                         #Whether to apply row dendrogram reordering.
        column_dend_reorder = TRUE,                       #Whether to apply column dendrogram reordering. 
        show_row_dend = FALSE,                            #Whether to show row dendrogram clustering.
        row_dend_width = unit(10, "mm"),                  #Set width of row dendrograms.
        show_column_dend = FALSE,                         #Whether to show column dendrogram clustering.
        width = unit(3, "in"),                            #Set heatmap width.
        height = unit(3.5, "in"),                         #Set heatmap height.
        heatmap_legend_param = lgd_list,                  #Reference object for legend parameters.
        #show_heatmap_legend = FALSE,                     #Uncomment to hide heatmap legend.
        name = "Z-score")                                 #Set title.

ht_selected = draw(ht_selected, heatmap_legend_side = "bottom") #Draws heatmap with legend at the bottom position.

#Output settings for each heatmap (W = width, H = height)
#2D_ECM: W = 3 x H = 3.5 | Output svg: W = 5 x H = 5
#2D_Secreted: W = 3 x H = 6.5 | Output svg: W = 4 x H = 4.5
#2D_Glycoproteins: W = 3 x H = 3.5 | Output svg: W = 4 x H = 4.5

svg(filename = "2D_Heatmap_Secreted.svg", width = 4, height = 4.5)
draw(ht_selected, heatmap_legend_side = "bottom")
dev.off()


In large Heatmaps, in order to avoid visual cluttering by labeling every gene, it is often valuable to label only a subset of genes.

#Heatmap parameters
col_fun <- colorRamp2(c(-2, 0, 2),                            #Create segments for the color gradient.
                      c("#2166AC", "white", "#B2182B"))       #Create color gradient with the specified color codes.

lgd_list <- list(title = "Z-score",                           #Set legend title.
                title_gp = gpar(fontsize = 12),               #Set font size for legend title.
                legend_height = unit(2.5, "cm"),              #Set height of the legend body.
                legend_width = unit(5, "cm"),                 #Set width of the legend body.
                grid_width = unit(0.4, "cm"),                 #Set width of each legend grid.
                direction = "horizontal",                     #Whether scale is 'horizontal' or 'vertical'
                title_position = "topcenter",                 #Set position of the title.
                gap = unit(4, "mm"))                          #Set gap between heatmap and legend.


#Create vector with subset of genes to label
Glycoproteins_select_label = c("ANGPT1", "B3GNT8", "MGAT4B", "EDNRB", "NDNF", "ADAMTS15", "ST6GALNAC5", "BMP4", "CDH8", "COL21A1", "IL34", "ICAM1", "NOTCH4", "OMD", "SEMA3D", "VCAM1")
Secreted_select_label = c("WNT2", "WNT16", "CXCL1", "CXCL2", "BMP4", "COL22A1", "EDN1", "GDF6", "IL1B", "CEMIP", "LIPG", "SCG5", "MXRA5", "IFNE", "SPP1", "ANGPT1", "NDNF", "KITLG", "AKR1B10")

#Assign genes subset to a static object for easily switching between plots
Genes_Label = Secreted_select_label

#Identify indices of the row names in the matrix that correspond to the genes listed in the vector 'Genes_Label' 
mark_at = which(rownames(vst_matSelected_z) %in% Genes_Label)

#Extract the row names of the matrix that correspond to indices in 'mark_at'. This step is a double-check to ensure that the selected rows do indeed match the original 'Genes_Label' vector.
Genes_DoubleCheck <- rownames(vst_matSelected_z)[mark_at]

#Check whether the two vectors contain the same elements, regardless of their order.
setequal(Genes_DoubleCheck, Genes_Label) #TRUE -> proceed to labeling.
#Note: Use 'Genes_DoubleCheck' object for labeling, because it outputs Gene symbols in the same order as 'mark_at'. This is necessary because 'mark_at' extracts row name numbers, which are automatically ordered numerically in the output vector.

#'anno_mark' function in ComplexHeatmap package enables linking heatmap annotation with customized labels.
foo = anno_mark(at = mark_at,                                 #Numeric index from original matrix.
                #link_width = unit(5, "mm"),                  #Uncomment to specify label link width.
                padding = 0.75,                               #Padding space between neighboring labels.
                labels = Genes_DoubleCheck,                   #Corresponding labels.
                labels_gp = gpar(fontsize = 10),              #Sets font size.
                which = "row")                                #Whether 'column' or 'row' annotation.

ht_selected_label <- Heatmap(vst_matSelected_z,               #Matrix input for heatmap.
                 col = col_fun,                               #Vector of colors for interpolation.
                 rect_gp = gpar(col = "grey30", lwd = 0.15),  #Border line color and width of each cell.
                 show_column_names = FALSE,                   #Whether to show column labeling.
                 show_row_names = FALSE,                      #Whether to show row labeling.
                 #row_names_gp = gpar(fontsize = 4),          #Uncomment to specify row label font size.
                 #row_names_side = "left",                    #Uncomment to specify row label side.
                 clustering_distance_columns = "pearson",     #Set clustering method for column dendrogram.
                 clustering_distance_rows = "pearson",        #Set clustering method for row dendrogram.
                 row_dend_reorder = FALSE,                    #Whether to apply row dendrogram reordering.
                 column_dend_reorder = TRUE,                  #Whether to apply column dendrogram reordering.
                 show_row_dend = FALSE,                       #Whether to show row dendrogram clustering.
                 show_column_dend = FALSE,                    #Whether to show column dendrogram clustering.
                 width = unit(3, "in"),                       #Set heatmap width.
                 height = unit(3.5, "in"),                    #Set heatmap height.
                 heatmap_legend_param = lgd_list,             #Reference object for legend parameters.
                 name = "Z-score")                            #Set title.

ht_merge = ht_selected_label + rowAnnotation(mark = foo)
ht_merge = draw(ht_merge, heatmap_legend_side = "bottom", align_heatmap_legend = "heatmap_left") #Note: 'align_heatmap_legend' = 'heatmap_center' position is offset because heatmap has been merged with 'rowAnnotation'.

svg(filename = "2D_Heatmap_Secreted_CompactLabel.svg", width = 4.5, height = 4.5)
dev.off()

LS0tDQp0aXRsZTogIlJOQVNlcSBhbmFseXNpcyAtIFIgUGlwZWxpbmUiDQphdXRob3I6ICJQZWRybyBMYXZyYWRvciINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KVGhpcyBwaXBlbGluZSB3YXMgY3JlYXRlZCB1c2luZyB0aGUgZm9sbG93aW5nIHJlc291cmNlczoNCg0KKiBbUl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvYmluL3dpbmRvd3MvYmFzZS8pDQoqIFtSU3R1ZGlvXShodHRwczovL3Bvc2l0LmNvL2Rvd25sb2FkL3JzdHVkaW8tZGVza3RvcC8pDQoNCldpdGhpbiB0aGUgUlN0dWRpbyBmaWxlICgqKi5ybWQqKiksIGVhY2ggY29kZSBjaHVuayBjYW4gYmUgZXhlY3V0ZWQgYnkgY2xpY2tpbmcgdGhlICoqUnVuKiogYnV0dG9uIHdpdGhpbiBlYWNoIGNodW5rIG9yIGJ5IHBsYWNpbmcgdGhlIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICoqQ250cmwrU2hpZnQrRW50ZXIqKi4NCg0KQWZ0ZXIgaW5zdGFsbGluZyAqUiogYW5kICpSU3R1ZGlvKiwgdGhlIGZvbGxvd2luZyBCaW9jb25kdWN0b3IgUiBwYWNrYWdlcyBhcmUgbmVjZXNzYXJ5IGZvciBwcm9jZXNzaW5nIFJOQVNlcSByYXcgZGF0YSwgY29uZHVjdGluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBhbmQgZGF0YSB2aXN1YWxpemF0aW9uOg0KDQoqIFtERVNlcTJdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9ERVNlcTIuaHRtbCkgLSAqRGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcyoNCiogW2VkZ2VSXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvZWRnZVIuaHRtbCkgLSAqRGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcyoNCiogW0Fubm90YXRpb25EYmldKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9Bbm5vdGF0aW9uRGJpLmh0bWwpIC0gKkdlbmUgSUQgY29udmVyc2lvbioNCiogW29yZy5Icy5lZy5kYl0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvZGF0YS9hbm5vdGF0aW9uL2h0bWwvb3JnLkhzLmVnLmRiLmh0bWwpIC0gKkdlbm9tZSBhbm5vdGF0aW9uIGRhdGFiYXNlIGZvciBIdW1hbioNCiogW0NvbXBsZXhIZWF0bWFwXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvQ29tcGxleEhlYXRtYXAuaHRtbCkgLSAqQWR2YW5jZWQgaGVhdG1hcCBkYXRhIHZpc3VhbGl6YXRpb24qDQoqIFtFbmhhbmNlZFZvbGNhbm9dKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9FbmhhbmNlZFZvbGNhbm8uaHRtbCkgLSAqQWR2YW5jZWQgdm9sY2FubyBwbG90IGRhdGEgdmlzdWFsaXphdGlvbioNCg0KDQpGb3IgaW5zdGFsbGluZyBwYWNrYWdlcywgZXhlY3V0ZSB0aGUgY29kZSBvbiB0aGUgKipJbnN0YWxsYXRpb24qKiBzZWN0aW9uIGluIHRoZSBjb3JyZXNwb25kaW5nIEJpb2NvbmR1Y3RvciBwYWdlLg0KDQpGb3IgaW5zdGFuY2UsIGZvciBpbnN0YWxsaW5nICoqREVTZXEyKio6DQoNCmBgYHtyIFBhY2thZ2UgSW5zdGFsbGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KaWYgKCFyZXF1aXJlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpDQpCaW9jTWFuYWdlcjo6aW5zdGFsbCgiREVTZXEyIikNCmBgYA0KDQoNClRoZSByZW1haW5pbmcgcGFja2FnZXMgYXJlIHBhcnQgb2YgdGhlIENvbXByZWhlbnNpdmUgUiBBcmNoaXZlIE5ldHdvcmsgKENSQU4pLCB3aGljaCBpcyB0aGUgb2ZmaWNpYWwgUiBwYWNrYWdlcyByZXBvc2l0b3J5LiBUaGVzZSBjYW4gYmUgaW5zdGFsbGVkIGluIFJTdHVkaW8gYnkgZ29pbmcgdG8gKipUb29scyoqIOKGkiAqKkluc3RhbGwgUGFja2FnZXMqKiBhbmQgaW4gdGhlICoqSW5zdGFsbCBmcm9tKiogb3B0aW9uIHNlbGVjdCAqKlJlcG9zaXRvcnkgKENSQU4pKiosIGZvbGxvd2VkIGJ5IHNwZWNpZnlpbmcgdGhlIGludGVuZGVkIHBhY2thZ2VzOg0KDQoqIFtnZ3Bsb3QyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2dwbG90Mi9pbmRleC5odG1sKSAtICpEYXRhIHZpc3VhbGl6YXRpb24gYW5kIGV4cG9ydCBvcHRpb25zKg0KKiBbZ2dhbHRdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ2FsdC9pbmRleC5odG1sKSAtICpBZGRzIGV4dHJhIGRhdGEgdmlzdWFsaXphdGlvbiBmbGV4aWJpbGl0eSoNCiogW2dncmVwZWxdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3JlcGVsL3ZpZ25ldHRlcy9nZ3JlcGVsLmh0bWwpIC0gKkFkZHMgZXh0cmEgZGF0YSB2aXN1YWxpemF0aW9uIGZsZXhpYmlsaXR5Kg0KKiBbdGV4dHNoYXBpbmddKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy90ZXh0c2hhcGluZy9pbmRleC5odG1sKSAtICpOZWNlc3NhcnkgZm9yIEVuaGFuY2VkVm9sY2FubyBwYWNrYWdlKg0KKiBbdGlkeXZlcnNlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdGlkeXZlcnNlL2luZGV4Lmh0bWwpIC0gKkRhdGEgcHJvY2Vzc2luZyBhbmQgdmlzdWFsaXphdGlvbioNCiogW1JDb2xvckJyZXdlcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1JDb2xvckJyZXdlci9pbmRleC5odG1sKSAtICpDb2xvciBzY2hlbWVzIGZvciBkYXRhIHZpc3VhbGl6YXRpb24qDQoqIFtjaXJjbGl6ZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2NpcmNsaXplL2luZGV4Lmh0bWwpIC0gKk5lY2Vzc2FyeSBmb3IgQ29sb3JSYW1wIHNjaGVtZSBpbiBoZWF0bWFwIGRhdGEgdmlzdWFsaXphdGlvbioNCiogW3BoZWF0bWFwXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcGhlYXRtYXAvcGhlYXRtYXAucGRmKSAtICpCYXNpYyBoZWF0bWFwIGRhdGEgdmlzdWFsaXphdGlvbioNCg0KPGJyPg0KQWZ0ZXIgaW5zdGFsbGluZyBldmVyeSByZXF1aXJlZCBwYWNrYWdlLCB0aGVzZSBsaWJyYXJpZXMgc2hvdWxkIGJlIGxvYWRlZCBpbnRvIFJTdHVkaW8gc28gdGhhdCB0aGVpciBjb21tYW5kcyBhbmQgZnVuY3Rpb25zIGFyZSBhdmFpbGFibGUgdG8gdXNlLiBUbyBkbyBzbywgZW50ZXI6DQpgYGB7ciBlY2hvPVQsIHJlc3VsdHM9J2hpZGUnfQ0KI0xvYWRpbmcgbGlicmFyaWVzDQpsaWJyYXJ5KCJERVNlcTIiKQ0KbGlicmFyeSgiZWRnZVIiKQ0KbGlicmFyeSgiQW5ub3RhdGlvbkRiaSIpDQpsaWJyYXJ5KCJvcmcuSHMuZWcuZGIiKQ0KbGlicmFyeSgiZ2dwbG90MiIpDQpsaWJyYXJ5KCJnZ2FsdCIpDQpsaWJyYXJ5KCJnZ3JlcGVsIikNCmxpYnJhcnkoInRleHRzaGFwaW5nIikNCmxpYnJhcnkoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQ0KbGlicmFyeSgiY2lyY2xpemUiKQ0KbGlicmFyeSgicGhlYXRtYXAiKQ0KbGlicmFyeSgiQ29tcGxleEhlYXRtYXAiKQ0KbGlicmFyeSgiRW5oYW5jZWRWb2xjYW5vIikNCmBgYA0KDQoqKk5vdGU6KiogTGlicmFyaWVzIHNob3VsZCBhbHdheXMgYmUgcmUtbG9hZGVkIHdoZW4gcmUtb3BlbmluZyB0aGUgc2NyaXB0Lg0KPGJyPg0KPGJyPg0KDQpBZnRlcndhcmRzLCBvcGVuIHRoZSByYXcgY291bnQgZGF0YSBmaWxlIGluIFJTdHVkaW8uIFRoaXMgZmlsZSBpcyBhIHRhYmxlIHRoYXQgcmVzdWx0cyBmcm9tIG1hcHBpbmcgdGhlIHNlcXVlbmNpbmcgcmVhZHMgdG8gYSByZWZlcmVuY2UgZ2Vub21lIGFuZCBkaXNwbGF5cyB0aGUgbnVtYmVyIG9mIHJlYWRzIGFzc2lnbmVkIHRvIGVhY2ggZ2VuZSwgaW4gZWFjaCBzYW1wbGUuIFRoaXMgdGFiLWRlbGltaXRlZCBmaWxlIGNvbnRhaW5zIGEgaGVhZGVyIHJvdyB3aXRoIGVhY2ggc2FtcGxlIG5hbWUgYW5kIGVhY2ggcm93IG5hbWUgcmVwcmVzZW50cyBhIHVuaXF1ZSBFbnNlbWJsIGdlbmUgSUQgKEVOU0cpLg0KDQpJbiB0aGlzIHdvcmssIHRoZSBmaWxlICoqIjJEX2NvdW50cy50eHQiKiogd2FzIHVzZWQgZm9yIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5hbHlzaXMgb2YgKioyRCBOYXRpdmUgaEFTQ3MqKiB2cyAqKjJEIEdseWNvZW5naW5lZXJlZCBoQVNDcyoqLiBGb3IgYXNzZXNzaW5nIHRoZSBpbXBhY3Qgb2YgY2VsbC1jZWxsIHRldGhlcmluZyBpbiB0aGUgdHJhbnNjcmlwdG9tZSwgKioyRCBHbHljb2VuZ2luZWVyZWQgaEFTQ3MqKiB2cyAqKjNEIENlbGxnZWxzKiogc2FtcGxlcyB3ZXJlIHBvb2xlZCBpbnRvICoqIjJEdjNEX2NvdW50cy50eHQiKiouDQoNCjxicj4NCioqRm9yIGVhc2Ugb2YgY29tcHJlaGVuc2lvbiwgZWFjaCBmdW5jdGlvbiBpcyBkZXNjcmliZWQgbGluZS1ieS1saW5lIGluIGNvbW1lbnRlZCBkZXNjcmlwdGlvbnMuIEZvciBmdXJ0aGVyIGluZm9ybWF0aW9uLCBwbGVhc2UgcmVmZXIgdG8gZWFjaCBwYWNrYWdlJ3MgdmlnbmV0dGUgY29udGFpbmluZyB0aGUgY29tcHJlaGVuc2l2ZSBjb21tYW5kIGxpc3QuKioNCg0KPGJyPg0KKipGaXJzdCwgUk5BU2VxIGFuYWx5c2lzIGluIDJEIGNvbmRpdGlvbnMgd2FzIGNvbmR1Y3RlZDoqKg0KYGBge3IgUmVhZCAyRCBjb3VudHN9DQojUmVhZHMgY291bnQgdGFibGUgYW5kIGFzc2lnbnMgaXQgdG8gYSB2YXJpYWJsZSBjYWxsZWQgIkNvdW50cyIuDQpDb3VudHMgPC0gcmVhZC50YWJsZSgiMkRfY291bnRzLnR4dCIsIGhlYWRlciA9IFRSVUUsIHJvdy5uYW1lcyA9IDEsIHNlcCA9Ilx0IikNCkNvdW50cw0KYGBgDQoqKk5vdGU6KiogQmVmb3JlIHN0YXJ0aW5nIHRoZSBhbmFseXNpcywgKipjb25maXJtIHRoYXQgdGhlIHJhdyBjb3VudHMgdGFibGUgY29udGFpbnMgdGhlIGFjdHVhbCB1bnByb2Nlc3NlZCByZWFkcyoqIGFuZCBub3QgdGhlIG91dHB1dCBvZiBhIHByZXZpb3VzIERFU2VxMiB3b3JrZmxvdy4gUmF3IGNvdW50IHZhbHVlcyBhcmUgc3RvcmVkIGFzIGludGVnZXJzLCB3aGVyZWFzIG5vcm1hbGl6ZWQgY291bnRzIGFyZSBkZWNpbWFscyBudW1iZXJzLiBERVNlcTIgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgY2FuIG9ubHkgYmUgY29uZHVjdGVkIG9uIHJhdyB1bnByb2Nlc3NlZCBjb3VudHMuDQoNCmBgYHtyIEZvcm1hdHMgYW5kIHNhdmVzIDJEIGNvdW50c30NCiNDcmVhdGVzIGRhdGEgZnJhbWUgY2FsbGVkICJjb2xkYXRhIiB0aGF0IGFzc2lnbnMgZXhwZXJpbWVudGFsIGNvbmRpdGlvbnMgKCIyRENvbnRyb2wiIG9yICIyREdseSIpIHRvIGVhY2ggc2FtcGxlIGFuZCBzdG9yZXMgdGhpcyBmYWN0b3IgaW4gdGhlICJ0cmVhdG1lbnQiIGNvbHVtbi4gQWxzbyByZW5hbWVzIHRoZSBvcmlnaW5hbCBzYW1wbGUgbmFtZXMgaW4gdGhlIC5iYW0gZmlsZSB0byBzaG9ydGVyIGFuZCBjb252ZW5pZW50IElEcy4NCmNvbGRhdGEgPC0gRGF0YUZyYW1lKGlkID0gYygiMkRDMSIsICIyREMyIiwgIjJEQzMiLCAiMkRDNCIsICIyREM1IiwgIjJERzEiLCAiMkRHMiIsICIyREczIiwgIjJERzQiLCAiMkRHNSIpLCB0cmVhdG1lbnQ9IGZhY3RvcihjKHJlcCgiMkRDb250cm9sIiwgdGltZXMgPSA1KSwgcmVwKCIyREdseSIsIHRpbWVzID0gNSkpLCBsZXZlbHMgPSBjKCIyRENvbnRyb2wiLCAiMkRHbHkiKSkpDQoNCiNTYXZlcyB0aGUgZm9ybWF0dGVkIGNvdW50cyB0YWJsZSB0byBhIC50eHQgZmlsZS4NCndyaXRlLnRhYmxlKENvdW50cywgZmlsZSA9ICIyRF9jb3VudHNfdjIudHh0Iiwgc2VwID0gIlx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpDQpgYGANCg0KYGBge3IgU2hvd3MgY29sZGF0YX0NCmNvbGRhdGENCmBgYA0KDQo8YnI+DQpOZXh0LCBhICoqcHJlLWZpbHRlcmluZyoqIHN0cmF0ZWd5IGlzIGFwcGxpZWQgdG8gdGhlICoqQ291bnRzKiogdGFibGUuIEJlZm9yZSBwcm9jZWVkaW5nIHdpdGggZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMsIGl0IGlzIGltcG9ydGFudCB0byBmaWx0ZXIgb3V0IGdlbmVzIHRoYXQgY29uc2lzdGVudGx5IHByZXNlbnQgZXh0cmVtZWx5IGxvdyBleHByZXNzaW9uLiBUaGlzIHJlZHVjZXMgbXVsdGlwbGUgdGVzdGluZyBidXJkZW4gYW5kIGhlbHBzIGluIGluY3JlYXNpbmcgdGhlIHN0YXRpc3RpY2FsIHBvd2VyIG9mIHRoZSBhbmFseXNpcywgd2hpbGUga2VlcGluZyBnZW5lcyBvZiBpbnRlcmVzdC4NCg0KSGVyZWluLCAqKmNvdW50cyBwZXIgbWlsbGlvbiAoQ1BNKSoqIGFyZSB1c2VkIGZvciAqKnByZS1maWx0ZXJpbmcqKiByYXRoZXIgdGhhbiAqKnJhdyBjb3VudHMqKiwgYXMgKipDUE0qKiBhY2NvdW50cyBmb3IgZGlmZmVyZW5jZXMgaW4gKipsaWJyYXJ5IHNpemVzKiogKGkuZS4sIHNlcXVlbmNpbmcgZGVwdGggPSB0b3RhbCBudW1iZXIgb2YgY291bnRzKSBhY3Jvc3Mgc2FtcGxlcywgZW5zdXJpbmcgYSBtb3JlIHJvYnVzdCBjb21wYXJpc29uLiAqRm9yIGluc3RhbmNlLCBpZiBzYW1wbGVzIHlpZWxkZWQgdW5ldmVuIGxpYnJhcnkgc2l6ZXMgKGUuZy4gMTUgTSB2cyA0MCBNKSwgYSBmaWx0ZXJpbmcgY3JpdGVyaWEgc29sZWx5IGJhc2VkIG9uIHJhdyBjb3VudHMgd291bGQgbm90IGF2b2lkIGZhdm9yaW5nIGdlbmVzIHRoYXQgYXJlIGV4cHJlc3NlZCBpbiB0aGUgbGFyZ2VyIGxpYnJhcnkuKiAqKkNQTSoqIGlzIGNhbGN1bGF0ZWQgdGhyb3VnaCAqKmVkZ2VSKiogYXMgdGhlICoqcmF3IGNvdW50cyBkaXZpZGVkIGJ5IGxpYnJhcnkgc2l6ZSBhbmQgbXVsdGlwbGllZCBieSBvbmUgbWlsbGlvbioqLg0KDQoqKk5vdGU6KiogKipDUE0qKiBjYWxjdWxhdGlvbiB0aHJvdWdoICoqZWRnZVIqKiBwYWNrYWdlIGlzIG1vcmUgc29waGlzdGljYXRlZCB0aGFuIG1hbnVhbGx5IGFwcGx5aW5nIHRoZSBmb3JtdWxhIGFzIGl0IGFsc28gYXV0b21hdGljYWxseSBjb3JyZWN0cyBmb3IgbGlicmFyeSBjb21wb3NpdGlvbiB1c2luZyAqY2FsY05vcm1GYWN0b3JzKi4NCg0KQXMgYSBydWxlIG9mIHRodW1iLCBmb3IgKipsaWJyYXJ5IHNpemVzKiogb2YgYWJvdXQgMjAgTSByZWFkcywgYSAqKkNQTSA9IDAuNSoqIGlzIHVzZWQgYXMgaXQgY29ycmVzcG9uZHMgdG8gYSAqKnJhdyBjb3VudCoqIG9mIDEwIC0gMTUuDQoNCioqTm90ZToqKiBUbyB2aWV3IHRoZSBsaWJyYXJ5IHNpemUgZm9yIGVhY2ggc2FtcGxlIGVudGVyOg0KYGBge3IgU2hvd3MgTGlicmFyeSBzaXplLCBpbmNsdWRlPVRSVUV9DQpsaWJyYXJ5X3NpemUgPC0gY29sU3VtcyhDb3VudHMpDQpsaWJyYXJ5X3NpemUuZGYgPC0gYXMuZGF0YS5mcmFtZShsaWJyYXJ5X3NpemUpDQpyb3duYW1lcyhsaWJyYXJ5X3NpemUuZGYpIDwtIGNvbGRhdGEkaWQNCmxpYnJhcnlfc2l6ZS5kZg0KYGBgDQoNCg0KYGBge3IgQ1BNIFRocmVzaG9sZGluZyBDaGVjaywgcmVzdWx0cz1GQUxTRX0NCiNDcm9zcy1jaGVja2luZyB3aGV0aGVyIGEgQ1BNIHRocmVzaG9sZCBvZiAwLjUgY29ycmVzcG9uZHMgdG8gYXBwcm94aW1hdGVseSAxMCAtIDE1IGNvdW50cyBpbiB0aGVzZSBzYW1wbGVzLg0KbXlDUE1fY29sbmFtZXMgPSBjKCJDMSIsICJDMiIsICJDMyIsICJDNCIsICJDNSIsICJHMSIsICJHMiIsICJHMyIsICJHNCIsICJHNSIpDQpteUNQTSA8LSBjcG0oQ291bnRzKSAjZWRnZVIgY2FsY3VsYXRlcyB0aGUgQ291bnRzIFBlciBNaWxsaW9uIChDUE0pIHZhbHVlcyBmb3IgdGhlIFJhdyBDb3VudHMgb2JqZWN0Lg0KcGxvdChteUNQTVssMV0sIENvdW50c1ssMV0sIHhsYWI9IkNQTSIsIHlsYWI9IlJhdyBDb3VudHMiLCBtYWluPXBhc3RlKCJTYW1wbGUiLCBteUNQTV9jb2xuYW1lc1sxXSksIA0KICAgICB5bGltPWMoMCw1MCksIHhsaW09YygwLDMpKQ0KI0FkZHMgcmVmZXJlbmNlIGxpbmVzIGF0IHggPSAwLjUgQ1BNIGFuZCB5ID0gMTAgUmF3IENvdW50cw0KYWJsaW5lKHY9MC41KSArIGFibGluZShoPTEwKQ0KYGBgDQoNCkNvbnNpZGVyaW5nIGxpYnJhcnkgc2l6ZXMgaW4gdGhpcyBkYXRhc2V0IGFyZSBvbiB0aGUgb3JkZXIgb2YgMjAgTSwgYSB0aHJlc2hvbGQgZm9yIGdlbmVzIHdpdGggKipDUE0gPiAwLjUqKiB3YXMgZXN0YWJsaXNoZWQuIEFuIGFkZGl0aW9uYWwgcmVxdWlyZW1lbnQgZm9yICoqZXhwcmVzc2lvbiBpbiAzIG9yIG1vcmUgbGlicmFyaWVzKiogaXMgdXNlZCwgYXMgZWFjaCBncm91cCBjb250YWlucyA1IHJlcGxpY2F0ZXMuIEFwcGx5aW5nIGEgc3RyaW5nZW50ICoqcHJlLWZpbHRlcmluZyoqIHRocmVzaG9sZCBlbnN1cmVzIGEgbW9yZSByZWxpYWJsZSBhbmQgcm9idXN0IGFuYWx5c2lzLiBUaGlzIGNyaXRlcmlhIGVsaW1pbmF0ZXMgZ2VuZXMgdGhhdCBhcmUgdW5saWtlbHkgdG8gYmUgcmVsZXZhbnQgZHVlIHRvICoqKGkpKiogaW5jb25zaXN0ZW50IHJlYWRzIGFjcm9zcyBkaWZmZXJlbnQgc2FtcGxlcywgYW5kICoqKGlpKSoqIGluY3JlYXNlZCBmb2xkIGNoYW5nZSBhbmQgdmFyaWFuY2UgYXNzb2NpYXRlZCB3aXRoIGV4dHJlbWVseSBsb3cgY291bnRzLiBJbiBhZGRpdGlvbiwgdGhpcyBzZXR1cCBlbnN1cmVzIHRoYXQgYSBnZW5lIHdpbGwgYmUgcmV0YWluZWQgZXZlbiBpZiBpdCBpcyBvbmx5IGV4cHJlc3NlZCBpbiBvbmUgZXhwZXJpbWVudGFsIGNvbmRpdGlvbi4NCg0KDQpgYGB7ciBQcmUtZmlsdGVyaW5nLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPUZBTFNFfQ0KI1ByZS1maWx0ZXJpbmcgQ291bnRzIHRvIENQTSA+IDAuNSBpbiBhdCBsZWFzdCAzIGRpZmZlcmVudCBzYW1wbGVzDQprZWVwQ1BNIDwtIHJvd1N1bXMoY3BtKENvdW50cykgPiAwLjUpID49IDMNCkNQTUNvdW50cyA8LSBDb3VudHNba2VlcENQTSxdDQpucm93KENvdW50cykgICAgIzYxNTUyID0gVG90YWwgbnVtYmVyIG9mIG1hcHBlZCBnZW5lcw0KbnJvdyhDUE1Db3VudHMpICMxNDE5NCA9IE51bWJlciBvZiBnZW5lcyBhZnRlciBwcmUtZmlsdGVyaW5nDQpgYGANCg0KYGBge3IgUnVubmluZyBERVNlcTIsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9VFJVRX0NCiNSdW5uaW5nIERFU2VxMiBhbmFseXNpcw0KZGRzQ1BNIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gQ1BNQ291bnRzLCBjb2xEYXRhID0gY29sZGF0YSwgZGVzaWduID0gfnRyZWF0bWVudCkNCmRkc0NQTSA8LSBERVNlcShkZHNDUE0pDQpyZXNkZHNDUE0gPC0gcmVzdWx0cyhkZHNDUE0pDQpyZXNkZHNDUE0gI1Nob3cgREVTZXEyIHJlc3VsdHMgdGFibGUNCmBgYA0KYGBge3IgT3V0cHV0IE5vcm1hbGl6ZWQgQ291bnRzfQ0KI091dHB1dCBERVNlcTIgTm9ybWFsaXplZCBDb3VudHMgLSBOZWNlc3NhcnkgZm9yIHN1Ym1pdHRpbmcgUk5BU2VxIGRhdGFzZXRzIHRvIHRoZSBTUkEgcmVwb3NpdG9yeS4NCm5vcm1hbGl6ZWRfY291bnRzIDwtIGNvdW50cyhkZHNDUE0sIG5vcm1hbGl6ZWQ9VFJVRSkNCndyaXRlLnRhYmxlKG5vcm1hbGl6ZWRfY291bnRzLCBmaWxlID0gIjJEX25vcm1hbGl6ZWRjb3VudHMudHh0Iiwgc2VwID0gIlx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpDQpgYGANCg0KPGJyPg0KTmV4dCwgdG8gaW1wcm92ZSBpbnRlcnByZXRhYmlsaXR5LCBpdCBpcyB1c2VmdWwgdG8gY29udmVydCB0aGUgbWFwcGVkICoqRU5TRU1CTCBJRHMqKiAoZS5nLiwgRU5TRzAwMDAwMTE1NDE0KSB0byB0aGUgbW9yZSByZWNvZ25pemFibGUgKipHZW5lIFN5bWJvbHMqKiAoZS5nLiwgRk4xIGZvciB0aGUgRmlicm9uZWN0aW4gZ2VuZSkuIA0KDQpgYGB7ciBBc3NpZ24gR2VuZSBJRHMsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9VFJVRX0NCiNBZGRzIGEgbmV3IGNvbHVtbiAiZ2VuZUlEIiB0byB0aGUgcmVzdWx0cyB0YWJsZSBjb250YWluaW5nIHRoZSBjb3JyZXNwb25kaW5nIEdlbmUgU3ltYm9scyB0byBlYWNoIHJvdw0KR2VuZUlEcyA8LSBtYXBJZHMob3JnLkhzLmVnLmRiLA0KICAgICAgICAgICAgICBrZXlzID0gcm93Lm5hbWVzKHJlc2Rkc0NQTSksDQogICAgICAgICAgICAgIGtleXR5cGUgPSAiRU5TRU1CTCIsDQogICAgICAgICAgICAgIGNvbHVtbiA9ICJTWU1CT0wiKQ0KRU5TX2dlbmVJRHMgPC0gc3RhY2soR2VuZUlEcykNCnJlc2Rkc0NQTSRnZW5lSUQgPC0gRU5TX2dlbmVJRHMkdmFsdWVzDQpyZXNkZHNDUE0gI1Nob3cgdGhlIHVwZGF0ZWQgREVTZXEyIHJlc3VsdHMgdGFibGUgd2l0aCB0aGUgbmV3IGdlbmVJRCBjb2x1bW4NCmBgYA0KKipOb3RlOioqIEdlbmUgc3ltYm9scyAoJ2dlbmVJRCcgY29sdW1uKSB3aXRoICpOQSogdmFsdWVzIGFyZSB0eXBpY2FsbHkgcHNldWRvZ2VuZXMsIHNvbWUgb2YgdGhvc2UgYXNzb2NpYXRlZCB3aXRoIHByb2R1Y2luZyBhbnRpc2Vuc2UgUk5BIHRyYW5zY3JpcHRzLiBOb3QgZXZlcnkgRU5TRU1CTCBHZW5lIElEIGNvcnJlc3BvbmRzIHRvIGEgSEdOQyBHZW5lIFN5bWJvbCBlbnRyeS4NCg0KYGBge3IgT3V0cHV0IEZ1bGwgUmVzdWx0c30NCiNPdXRwdXQgZnVsbCByZXN1bHRzOiBOb3JtYWxpemVkIGNvdW50cyArIERFU2VxMiByZXN1bHRzIHRhYmxlDQpyZXN1bHRzX3N1bSA8LSBjYmluZChub3JtYWxpemVkX2NvdW50cywgcmVzZGRzQ1BNKQ0KI3dyaXRlLmNzdihyZXN1bHRzX3N1bSwgZmlsZSA9ICIyRF9mdWxsX3Jlc3VsdHMuY3N2IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpICMuQ1NWIGFsdGVybmF0aXZlIHRvIHVwbG9hZCBkYXRhDQp3cml0ZS50YWJsZShyZXN1bHRzX3N1bSwgZmlsZSA9ICIyRF9mdWxsX3Jlc3VsdHMudHh0Iiwgc2VwID0gIlx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpICMuVFhUIGZvciBiZXR0ZXIgZGF0YSBmZXRjaGluZw0KYGBgDQoNCjxicj4NCkFmdGVyIERFU2VxMiBwcm9jZXNzaW5nLCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBvZiBnZW5lcyBjYW4gYmUgY29uZHVjdGVkLiBJbiB0aGlzIHdvcmssIGdlbmVzIGFyZSBjb25zaWRlcmVkIHRvIGJlICoqRGlmZmVyZW50aWFsbHkgRXhwcmVzc2VkIEdlbmVzIChERUdzKSoqIGlmIHRoZXkgZXhoaWJpdCBhbiAqKmFkanVzdGVkIHAtdmFsdWUgPCAwLjA1KiogKCoqcGFkaioqLCBCZW5qYW1pbmktSG9jaGJlcmcgcHJvY2VkdXJlIGZvciBtdWx0aXBsZSB0ZXN0aW5nIGNvcnJlY3Rpb24pIGFuZCBwcmVzZW50ICoqbG9nMihmb2xkIGNoYW5nZSkgPiAxKiogb3IgKio8IC0xKiouDQoNClNwZWNpZmljYWxseSwgYSAqKmxvZzIoZm9sZCBjaGFuZ2UpID4gMSoqIHRyYW5zbGF0ZXMgaW50byBhbiAqKj4gMi1mb2xkIHVwcmVndWxhdGVkIGdlbmUgZXhwcmVzc2lvbioqLCB3aGVyZWFzIGEgKipsb2cyKGZvbGQgY2hhbmdlKSA8IC0xKiogaW5kaWNhdGVzIGEgKio8IDAuNSBmb2xkIGRvd25yZWd1bGF0aW9uKiouIEJ5IGNvbWJpbmluZyBib3RoIG9mIHRoZXNlIHRocmVzaG9sZHMsIHRoaXMgcm9idXN0IGNyaXRlcmlhIHByb3ZpZGVzIGdyZWF0ZXIgc3BlY2lmaWNpdHkgZm9yIGlkZW50aWZ5aW5nIGdlbmVzIHRoYXQgYXJlIG5vdCBvbmx5IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIGJ1dCBhcmUgYWxzbyBtb3JlIGxpa2VseSB0byBiZSBiaW9sb2dpY2FsbHkgcmVsZXZhbnQuDQoNCg0KYGBge3IgT3V0cHV0IERFR3MsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9RkFMU0V9DQojQW5hbHlzaXMgb2YgREVHcyBkaXN0cmlidXRpb24gZm9yIERvbnV0IFBsb3QNCg0KcmVzZGRzQ1BNIDwtIHJlc2Rkc0NQTVshaXMubmEocmVzZGRzQ1BNJHBhZGopLCBdICNDbGVhbi11cCBvZiBnZW5lcyBjb250YWluaW5nICdOQScgaW4gJ3BhZGonIGNvbHVtbi4gVGhpcyBvY2N1cnMgaW4gZ2VuZXMgZmlsdGVyZWQgb3V0IGJ5IERFU2VxMiB0aHJvdWdoIGF1dG9tYXRpYyBpbmRlcGVuZGVudCBmaWx0ZXJpbmcgb3IgY29udGFpbmluZyBhIHNhbXBsZSB3aXRoIGFuIGV4dHJlbWUgY291bnQgb3V0bGllciwgYXMgZGV0ZWN0ZWQgYnkgQ29vaydzIGRpc3RhbmNlLg0KDQpzaWdzIDwtIHJlc2Rkc0NQTVtyZXNkZHNDUE0kcGFkaiA8IDAuMDUsXSAgICAgICAjQ3JlYXRlcyBhIHN1YnNldCBvZiBnZW5lcyB0aGF0IG1lZXQgdGhlIHBhZGogPCAwLjA1IHRocmVzaG9sZC4NCnNpZ3NBTEwgPC0gc2lnc1thYnMoc2lncyRsb2cyRm9sZENoYW5nZSkgPiAxLF0gICNUb3RhbCBERUdzLCB1c2Ugb2YgYWJzb2x1dGUgbG9nMmZvbGQgY2hhbmdlIHZhbHVlcyAoJ2FicycpLg0Kc2lnc1VQIDwtIHNpZ3Nbc2lncyRsb2cyRm9sZENoYW5nZSA+IDEsXSAgICAgICAgI1VwcmVndWxhdGVkIERFR3MuDQpzaWdzRE9XTiA8LSBzaWdzW3NpZ3MkbG9nMkZvbGRDaGFuZ2UgPCAtMSxdICAgICAjRG93bnJlZ3VsYXRlZCBERUdzLg0KDQojU3VtbWFyeQ0KI2RpbShyZXNkZHNDUE0pICNUb3RhbCBnZW5lcyA9IDE0MTkzDQojZGltKHNpZ3MpICAgICAgI1RvdGFsIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZ2VuZXMgPSA0NjkyDQojZGltKHNpZ3NBTEwpICAgI1RvdGFsIERFR3MgPSA1NjgNCiNkaW0oc2lnc1VQKSAgICAjVXByZWd1bGF0ZWQgREVHcyA9IDE4MA0KI2RpbShzaWdzRE9XTikgICNEb3ducmVndWxhdGVkIERFR3MgPSAzODgNCg0KI091dHB1dCBERUdzDQpzaWdzQUxMLmRmIDwtIGFzLmRhdGEuZnJhbWUoc2lnc0FMTCkNCnNpZ3NBTEwuZGYkc3ltYm9sIDwtIG1hcElkcyhvcmcuSHMuZWcuZGIsIGtleXMgPSByb3duYW1lcyhzaWdzQUxMLmRmKSwga2V5dHlwZSA9ICJFTlNFTUJMIiwgY29sdW1uID0gIlNZTUJPTCIpICNBbHRlcm5hdGl2ZSB3YXkgdG8gYWRkIEdlbmUgU3ltYm9scyB0byBlYWNoIHJvdywgYXZhaWxhYmxlIHVwb24gY29udmVyc2lvbiB0byBhIGRhdGEuZnJhbWUgb2JqZWN0Lg0Kd3JpdGUuY3N2KHNpZ3NBTEwuZGYsICIyRF9ERUdzLmNzdiIsIHF1b3RlID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpDQoNCiNPdXRwdXQgVm9sY2FubyB0YWJsZQ0Kd3JpdGUuY3N2KHJlc2Rkc0NQTSwgIjJEX1ZvbGNhbm8uY3N2IiwgcXVvdGUgPSBGQUxTRSwgY29sLm5hbWVzID0gVFJVRSkNCmBgYA0KDQo8YnI+DQpOZXh0LCB0aGUgcXVhbGl0eSBvZiB0aGUgUk5BU2VxIGRhdGFzZXQgY2FuIGJlIHZhbGlkYXRlZCBieSBwbG90dGluZyB0aGUgKipwZXItZ2VuZSBkaXNwZXJzaW9uIGVzdGltYXRlcyB2ZXJzdXMgdGhlIG1lYW4gZXhwcmVzc2lvbioqLiBUaGUgdmlzdWFsaXphdGlvbiBvZiB0aGlzIHBsb3QgKCoqcGxvdERpc3BFc3RzKiopIGFsbG93cyBmb3IgcmFwaWRseSBjaGVja2luZyB3aGV0aGVyIHRoZSAqKmZpdHRlZCBtZWFuLWRpc3BlcnNpb24gcmVsYXRpb25zaGlwKiogKCpyZWQgdHJlbmQgbGluZSopIHNob3dzIGFuICoqYXBwcm9wcmlhdGUgZml0KiogdG8gdGhlIGRhdGEgYW5kIGVuc3VyZSB0aGUgKip2YWxpZGl0eSoqIG9mIGRpZmZlcmVudGlhbCB0ZXN0aW5nIGFzc3VtcHRpb25zIGluIGRvd25zdHJlYW0gYW5hbHlzaXMuDQoNCmBgYHtyIFBsb3QgRGlzcGVyc2lvbnN9DQojUGxvdCBmaXR0ZWQgbWVhbi1kaXNwZXJzaW9uIHJlbGF0aW9uc2hpcA0KcGxvdERpc3BFc3RzKGRkc0NQTSkNCmBgYA0KDQo8YnI+DQpJbiBhZGRpdGlvbiwgaXQgaXMgaW1wb3J0YW50IHRvIHBlcmZvcm0gYSBzY2F0dGVycGxvdCBvZiB0aGUgKipiaW9sb2dpY2FsIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbioqICgqKkJDVioqKSBhZ2FpbnN0IHRoZSBhdmVyYWdlIGFidW5kYW5jZSBvZiBlYWNoIGdlbmUuIEEgKipCQ1YgcGxvdCoqIHByb3ZpZGVzIGZ1cnRoZXIgdmlzdWFsaXphdGlvbiBvZiB0aGUgKipiaW9sb2dpY2FsIHZhcmlhYmlsaXR5KiogYWNyb3NzIHNhbXBsZXMgaW4gdGVybXMgb2YgZ2VuZSBleHByZXNzaW9uLCBhbmQgd2hldGhlciB0aGlzIHZhcmlhbmNlIGlzIGFkZXF1YXRlIGZvciBmaXR0aW5nLg0KDQoNCkFzIGZvdW5kIGJlbG93LCB0aGUgY29tbW9uIGRpc3BlcnNpb24gKCoqRGlzcCoqKSBpcyAqKjAuMDEzMzEqKiBhbmQgdGhlICoqQkNWKiogKHNxdWFyZSByb290IG9mICoqRGlzcCoqKSBpcyAqKjAuMTE1NCoqLiBUeXBpY2FsbHksIHRoZSBhc3ltcHRvdGljIHZhbHVlIGZvciAqKkJDVioqIHRlbmRzIHRvIGJlIHdpdGhpbiB0aGUgKiowLjA1IC0gMC4yKiogcmFuZ2UgZm9yIGNlbGwgbGluZSBleHBlcmltZW50cyBvciBnZW5ldGljYWxseSBpZGVudGljYWwgbWljZSwgd2hlcmVhcyBsYXJnZXIgdmFsdWVzICgqKj4gMC4zKiopIGNhbiBiZSBmb3VuZCBpbiBodW1hbiBzdWJqZWN0cyBkYXRhc2V0cy4gQXMgYSByZXN1bHQsIHRoaXMgKipCQ1YqKiBhbmFseXNpcyBmdXJ0aGVyIGNvbmZpcm1zIHRoZSB2YWxpZGl0eSBvZiB0aGUgZGF0YXNldCBmb3Igc3Vic2VxdWVudCBkb3duc3RyZWFtIGFuYWx5c2lzLCBhcyBpdCB3aWxsIGJlIGRlbW9uc3RyYXRlZCBiZWxvdy4NCg0KDQpgYGB7ciBlZGdlUiBQcm9jZXNzaW5nIGFuZCBCQ1YgUGxvdCwgbWVzc2FnZT1GQUxTRSxlY2hvPVRSVUUsIHJlc3VsdHM9J2hpZGUnfQ0KI2VkZ2VSIHByb2Nlc3NpbmcgZm9yIGZpdHRpbmcgYW5kIGNhbGN1bGF0aW9ucw0KY29uZGl0aW9uID0gZmFjdG9yKGMocmVwKCIyRENvbnRyb2wiLCB0aW1lcyA9IDUpLCByZXAoIjJER2x5IiwgdGltZXMgPSA1KSkpDQpkZ2VHbG0gPC0gREdFTGlzdChjb3VudHMgPSBDUE1Db3VudHMsIGdyb3VwID0gY29uZGl0aW9uKQ0Kc3RyKGRnZUdsbSkNCm5hbWVzKGRnZUdsbSkNCmRnZUdsbVtbInNhbXBsZXMiXV0NCmBgYA0KDQpgYGB7ciBCQ1YgdmFsdWUgYW5kIEJDViBQbG90LCBlY2hvPVRSVUV9DQojQ2FsY3VsYXRlIGNvbW1vbiBkaXNwZXJzaW9uIChEaXNwKSBhbmQgYmlvbG9naWNhbCBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24gKEJDVikNCmRlc2lnbiA8LSBtb2RlbC5tYXRyaXgofmNvbmRpdGlvbikNCmRnZUdsbUNvbURpc3AgPC0gZXN0aW1hdGVHTE1Db21tb25EaXNwKGRnZUdsbSwgZGVzaWduLCB2ZXJib3NlID0gVFJVRSkgI0Rpc3AgPSAwLjAxMzMxLCBCQ1YgPSAwLjExNTQNCg0KDQojUGxvdHRpbmcgQkNWIHNjYXR0ZXJwbG90DQpkZ2VHbG1UcmVuZERpc3AgPC0gZXN0aW1hdGVHTE1UcmVuZGVkRGlzcChkZ2VHbG1Db21EaXNwLCBkZXNpZ24pDQpkZ2VHbG1UYWdEaXNwIDwtIGVzdGltYXRlR0xNVGFnd2lzZURpc3AoZGdlR2xtVHJlbmREaXNwLCBkZXNpZ24pDQpwbG90QkNWKGRnZUdsbVRhZ0Rpc3ApDQpgYGANCg0KDQpgYGB7ciBFZGdlUiBTbWVhclBsb3QsIGluY2x1ZGU9RkFMU0V9DQojZWRnZVIgYWx0ZXJuYXRpdmUgdG8gVm9sY2FubyBQbG90DQpmaXQgPC0gZ2xtRml0KGRnZUdsbVRhZ0Rpc3AsIGRlc2lnbikNCmNvbG5hbWVzKGNvZWYoZml0KSkgIA0KbHJ0IDwtIGdsbUxSVChmaXQsIGNvZWYgPSAyKSAgDQp0dEdsbSA8LSB0b3BUYWdzKGxydCwgbiA9IEluZikgIA0Kc3VtbWFyeShkZUdsbSA8LSBkZWNpZGVUZXN0c0RHRShscnQsIHAgPSAwLjA1LCBhZGp1c3QgPSAiZmRyIikpDQp0YWdzR2xtIDwtIHJvd25hbWVzKGRnZUdsbVRhZ0Rpc3ApW2FzLmxvZ2ljYWwoZGVHbG0pXQ0KcGxvdFNtZWFyKGxydCwgZGUudGFncyA9IHRhZ3NHbG0pDQpgYGANCg0KPGJyPg0KUk5BU2VxIGRhdGFzZXRzIG9mdGVuIGNvbnRhaW4gdGhvdXNhbmRzIG9mIGdlbmVzIGFjcm9zcyBtdWx0aXBsZSBzYW1wbGVzLCBtYWtpbmcgaXQgZXh0cmVtZWx5IGNvbXBsZXggdG8gZGV0ZWN0IGFuZCBhbmFseXplIHBhdHRlcm5zIG9mIGdlbmUgZXhwcmVzc2lvbiBkYXRhLiBJbiB0aGlzIGNvbnRleHQsICoqUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyoqICgqKlBDQSoqKSB0cmFuc2Zvcm1zIGRhdGEgaW50byBhIHNldCBvZiB1bmNvcnJlbGF0ZWQgdmFyaWFibGVzIChpLmUuLCBwcmluY2lwYWwgY29tcG9uZW50cyksIHdoaWNoIGlzIHVzZWZ1bCBmb3IgcmVkdWNpbmcgZGF0YSBkaW1lbnNpb25hbGl0eSwgcHJvdmlkaW5nIGEgKipibGluZCoqIGFuZCAqKnVuYmlhc2VkIGFzc2Vzc21lbnQqKiBvZiBnZW5lIGV4cHJlc3Npb24gcGF0dGVybnMgYWNyb3NzIG11bHRpcGxlIHNhbXBsZXMgYW5kIGNvbmRpdGlvbnMuIFBDMSBkZXNjcmliZXMgdGhlIG1vc3QgdmFyaWF0aW9uIHdpdGhpbiB0aGUgZGF0YSwgUEMyIHRoZSBzZWNvbmQgbW9zdCwgYW5kIHNvIGZvcnRoLg0KDQpUaGVyZWZvcmUsICoqUENBKiogaXMgaGlnaGx5IHZhbHVhYmxlIGZvciAqKihpKSoqIGlkZW50aWZ5aW5nICoqZ2VuZSBleHByZXNzaW9uIHRyZW5kcyoqIChlLmcuLCBjb25maXJtaW5nIHRoZSBiaW9sb2dpY2FsIHJlbGV2YW5jZSBvZiB0aGUgdHJlYXRtZW50L2Rpc2Vhc2Ugb3IgZXhwZXJpbWVudGFsIGNvbmRpdGlvbiksICoqKGlpKSoqIGlkZW50aWZ5aW5nICoqY2x1c3RlcnMqKiBvZiBzYW1wbGVzIGFuZCB0aGVpciByZWxhdGlvbnNoaXBzLCBhbmQgKiooaWlpKSoqIHNjcmVlbmluZyBvdXQgYW55IHBvdGVudGlhbCAqKm91dGxpZXJzKiogb3IgKipiYXRjaCBlZmZlY3RzKiouIFZpc3VhbGl6aW5nIHRoZXNlIGVmZmVjdHMgYXNzaXN0cyBpbiBjb25maXJtaW5nIHRoZSBoeXBvdGhlc2lzIHRlc3RlZCBpbiBmdXJ0aGVyICoqREVHcyoqIGRvd25zdHJlYW0gYW5hbHlzaXMuDQoNCg0KVG8gY3JlYXRlIGEgKipQQ0EgcGxvdCoqLCBmaXJzdCBhICoqdnN0KCkqKiAoKmkuZS4sIHZhcmlhbmNlLXN0YWJpbGl6aW5nIHRyYW5zZm9ybWF0aW9uKikgZnVuY3Rpb24gc2hvdWxkIGJlIGFwcGxpZWQgdG8gcmVtb3ZlIHRoZSBkZXBlbmRlbmNlIG9mIHRoZSB2YXJpYW5jZSBvbiB0aGUgbWVhbi4gVGhpcyBpcyBiZWNhdXNlIGFuYWx5c2lzIG9mIG11bHRpLWRpbWVuc2lvbmFsIGRhdGEgKHN1Y2ggYXMgUENBKSB3b3JrcyBiZXN0IGZvciBob21vc2tlZGFzdGljIGRhdGEgKGkuZS4sIGNvbnNpc3RlbnQgdmFyaWFiaWxpdHkpLCB3aGVyZWFzIGluIFJOQVNlcSBkYXRhIHZhcmlhbmNlIGluY3JlYXNlcyB3aXRoIHRoZSBtZWFuIHZhbHVlcy4gVW5saWtlIHRoZSBvdGhlciBERVNlcTIgZnVuY3Rpb24gKGkuZS4sICpybG9nKCkqKSBmdW5jdGlvbiBmb3IgdGhpcyBwdXJwb3NlLCAqKnZzdCgpKiogaXMgbW9yZSBzZW5zaXRpdmUgdG8gc2l6ZSBmYWN0b3IgYW5kIGFsc28gbm9ybWFsaXplcyB3aXRoIHJlc3BlY3QgdG8gbGlicmFyeSBzaXplLg0KDQoNCmBgYHtyIDJEIFBDQX0NCiNPdXRwdXQgMkQgUENBIFBsb3QNCnZzZGF0YSA8LSB2c3QoZGRzQ1BNLCBibGluZCA9IEZBTFNFKSAjQXBwbHkgdmFyaWFuY2Utc3RhYmlsaXppbmcgdHJhbnNmb3JtYXRpb24gdG8gREVTZXEgb2JqZWN0ICdkZHNDUE0nDQojQnkgZGVmYXVsdCBib3RoIHRoZXNlIGZ1bmN0aW9ucyBhcmUgKipibGluZCoqIHRvIHRoZSBzYW1wbGUgZGVzaWduIGZvcm11bGEgZ2l2ZW4gdG8gREVTZXEyIGluIERFU2VxRGF0YVNldEZyb21NYXRyaXgoKSwgaG93ZXZlciB0aGlzIGlzIG5vdCBhcHByb3ByaWF0ZSBpZiBvbmUgZXhwZWN0cyBsYXJnZSBkaWZmZXJlbmNlcyBpbiBjb3VudHMgZXhwbGFpbmVkIGJ5IGRpZmZlcmVuY2VzIGluIGV4cGVyaW1lbnRhbCBkZXNpZ24uIEluIHN1Y2ggY2FzZXMsIHRoZSBibGluZCBwYXJhbWV0ZXIgc2hvdWxkIGJlIHNldCB0byAnRkFMU0UnIGFzIHJlY29tbWVuZGVkIGluIERFU2VxMiB2aWduZXR0ZS4gDQoNCg0KI3Bsb3RQQ0EodnNkYXRhLCBpbnRncm91cCA9ICJ0cmVhdG1lbnQiKSAgICAgICAgICAjUHJldmlldyBQQzEgYW5kIFBDMiAlIGZvciBjb3JyZWN0IGF4aXMgbGFiZWxpbmcuDQpQQ0FyYXcgPC0gcGxvdFBDQSh2c2RhdGEsIGludGdyb3VwID0gInRyZWF0bWVudCIpICNDcmVhdGUgYSBQQ0EgcGxvdCB1c2luZyAndnNkYXRhJyBhbmQgZ3JvdXBzIGl0IGJ5ICd0cmVhdG1lbnQnLg0KZ3JvdXAuY29sb3JzIDwtIGMoIiM2MTlDRkYiLCIjMDBDMTlGIikgICAgICAgICAgICAjVmVjdG9yIGNvbnRhaW5pbmcgY29sb3IgY29kZXMgdG8gYmUgdXNlZCBpbiBlYWNoIGdyb3VwLg0KbmV3X3BjYSA8LSBnZ3Bsb3QoUENBcmF3W1siZGF0YSJdXSwgICAgICAgICAgICAgICAjQ3JlYXRlIGEgZ2dwbG90IHVzaW5nICdkYXRhJyBkYXRhLmZyYW1lIHdpdGhpbiAnUENBcmF3JyBvYmplY3QuIA0KICBhZXMoUEMxLCBQQzIsIGNvbG9yPWdyb3VwKSkgKyAgICAgICAgICAgICAgICAgICAjQ29uc3RydWN0IGFlc3RoZXRpYyBtYXBwaW5nIHVzaW5nIFBDMSBhbmQgUEMyLg0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZ3JvdXAuY29sb3JzKSArICAgICAjU3BlY2lmeSBhIHZlY3RvciBvZiBjb2xvcnMuDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIuNSkgKyAgICAgICAgICAgICAgICAgICAgICAgICNDaGFuZ2UgbWFya2VyIHNpemUuDQogIHhsYWIoIlBDMSAoNzklKSIpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNUZXh0IHVzZWQgZm9yIFggYXhpcy4NCiAgeWxhYigiUEMyICg5JSkiKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1RleHQgdXNlZCBmb3IgWSBheGlzLg0KICB5bGltKC0xMCwgMTApICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTG93ZXIvdXBwZXIgbGltaXRzIGZvciBZIGF4aXMuDQogIHhsaW0oLTEyLCAxMikgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb3dlci91cHBlciBsaW1pdHMgZm9yIFggYXhpcy4NCiAgdGhlbWVfZ3JleSgpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1NldCBhIGdyZXkgYmFja2dyb3VuZCB3aXRoIHdoaXRlIGdyaWRsaW5lcy4NCnRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAgICAgI0N1c3RvbWl6ZSBzaXplIGFuZCBzdHlsZSBvZiBheGlzIHRpdGxlcyBhbmQgdGV4dC4NCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksDQogIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIikpDQoNCm5ld19wY2ENCmdnc2F2ZSgiMkRfUENBLnN2ZyIsIG5ld19wY2EsIGRwaSA9IDYwMCwgd2lkdGggPSAyLjYsIGhlaWdodCA9IDIsIHVuaXRzID0gImluIiwgc2NhbGUgPSAyKSAjRXhwb3J0cyBwbG90IGluIC5zdmcNCmBgYA0KPGJyPg0KQXBhcnQgZnJvbSAqKlBDQSoqLCBhbm90aGVyIGltcG9ydGFudCBhbmFseXNpcyB0byBwZXJmb3JtIGlzIHRvIGRldGVybWluZSB3aGV0aGVyICoqaW50ZXJncm91cCB2YXJpYWJpbGl0eSoqIC0gd2hpY2ggcmVwcmVzZW50cyBkaWZmZXJlbmNlcyBiZXR3ZWVuIGV4cGVyaW1lbnRhbCBjb25kaXRpb25zIGluIGNvbXBhcmlzb24gd2l0aCBjb250cm9sIGNvbmRpdGlvbnMgLSBpcyBncmVhdGVyIHRoYW4gdGhlICoqaW50cmFncm91cCB2YXJpYWJpbGl0eSoqLCByZXByZXNlbnRpbmcgdGVjaG5pY2FsIG9yIGJpb2xvZ2ljYWwgdmFyaWFuY2UuIFRoaXMgaXMgYWNoaWV2ZWQgYnkgKipjYWxjdWxhdGluZyBkaXN0YW5jZSoqIGFzIHJlcHJlc2VudGVkIGJ5IGNvcnJlbGF0aW9uIGFjcm9zcyBzYW1wbGVzLCB0eXBpY2FsbHkgdXNpbmcgdGhlICoqUGVhcnNvbidzIGNvcnJlbGF0aW9uIHBsb3QqKi4gDQoNCioqUGVhcnNvbidzKiogY29lZmZpY2llbnQgcmVmbGVjdHMgdGhlIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiAyIHZhcmlhYmxlcyBhY2NvdW50aW5nIGZvciBkaWZmZXJlbmNlcyBpbiBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24uIEZvciBpbnN0YW5jZSwgdGhlICoqbW9yZSBzaW1pbGFyIHRoZSBnZW5lIGV4cHJlc3Npb24gcHJvZmlsZXMgZm9yIGFsbCB0cmFuc2NyaXB0cyoqIGFyZSBiZXR3ZWVuIHR3byBzYW1wbGVzLCB0aGUgKipoaWdoZXIgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50Kiogd2lsbCBiZS4gVGhlc2UgY29lZmZpY2llbnRzIGFyZSBjYWxjdWxhdGVkIGJldHdlZW4gYWxsIHNhbXBsZXMgYW5kIGFyZSB0aGVuICoqdmlzdWFsaXplZCBhcyBhIGhlYXRtYXAqKi4NCg0KU2ltaWxhciB0byBQQ0EsIHRoZSAqKlBlYXJzb24ncyBjb3JyZWxhdGlvbiBwbG90KiogcHJvdmlkZXMgYW4gb3ZlcnZpZXcgb2YgdGhlICoqb3ZlcmFsbCBzdHJlbmd0aCBvZiB0aGUgYmlvbG9naWNhbCBlZmZlY3QqKiBvZiB0aGUgZXhwZXJpbWVudCwgYXNzZXNzaW5nIHdoZXRoZXIgcmVwbGljYXRlcyBhbmQgZGlmZmVyZW50IGNvbmRpdGlvbnMgZ3JvdXAgdG9nZXRoZXIsIGFzIHdlbGwgYXMgaWRlbnRpZnkgb3V0bGllcnMgdGhhdCB3ZXJlIG5vdCBleGNsdWRlZCBkdXJpbmcgdXBzdHJlYW0gc3RlcHMgKGUuZy4sIHNhbXBsZSBsYWJlbGluZyBvciBnZW5vbWljIGFsaWdubWVudCkuDQoNCg0KDQpgYGB7ciAyRCBTYW1wbGUgRGlzdGFuY2VzIENvcnJlbGF0aW9ufQ0KI091dHB1dCAyRCBQZWFyc29uJ3MgQ29ycmVsYXRpb24gUGxvdA0KdnNkYXRhIDwtIHZzdChkZHNDUE0sIGJsaW5kID0gRkFMU0UpICAgICAgICAgICAgICAgICAgICAjQXBwbHkgdmFyaWFuY2Utc3RhYmlsaXppbmcgdHJhbnNmb3JtYXRpb24uDQpzYW1wbGVEaXN0cyA8LSBjb3IobWV0aG9kID0gInBlYXJzb24iLCBhc3NheSh2c2RhdGEpKSAgICNDYWxjdWxhdGUgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMuDQpzYW1wbGVEaXN0TWF0cml4IDwtIGFzLm1hdHJpeChzYW1wbGVEaXN0cykgICAgICAgICAgICAgICNDb252ZXJ0IHRvIG1hdHJpeCBmb3JtYXQuDQpyb3duYW1lcyhzYW1wbGVEaXN0TWF0cml4KSA8LSBwYXN0ZSh2c2RhdGEkaWQpICAgICAgICAgICNMYWJlbCBTYW1wbGUgbmFtZXMuDQpjb2xuYW1lcyhzYW1wbGVEaXN0TWF0cml4KSA8LSBwYXN0ZSh2c2RhdGEkaWQpICAgICAgICAgICNMYWJlbCBTYW1wbGUgbmFtZXMuDQpjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJCbHVlcyIpKSgyNTUpICNDb2xvciBwYWxldHRlIHJhbmdlIGZvciBoZWF0bWFwIHZpc3VhbGl6YXRpb24uDQpTYW1wbGVEaXN0YW5jZSA9IHBoZWF0bWFwKHNhbXBsZURpc3RNYXRyaXgsIGNvbD1jb2xvcnMpICNHZW5lcmF0ZSBoZWF0bWFwIHdpdGggJ3NhbXBsZURpc3RNYXRyaXgnIGFuZCAnY29sb3JzJyBpbnB1dHMuDQpTYW1wbGVEaXN0YW5jZSAjZ2dzYXZlKCJTRF8yRF9QZWFyc29uLnN2ZyIsIFNhbXBsZURpc3RhbmNlLCBkcGkgPSA2MDAsIHdpZHRoID0gMi41NSwgaGVpZ2h0ID0gMiwgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpIA0KYGBgDQoNCmBgYHtyIEV1Y2xpZGVhbiBEaXN0YW5jZXMgQ29ycmVsYXRpb24gREVTZXEyIHZpZ25ldHRlfQ0KI0FsdGVybmF0aXZlOiBFdWNsaWRlYW4gRGlzdGFuY2VzIENvcnJlbGF0aW9uIFBsb3QsIGFzIGRlc2NyaWJlZCBpbiBERVNlcTIgdmlnbmV0dGUNCnNhbXBsZURpc3RzX0V1Y2xpZGVhbiA8LSBkaXN0KHQoYXNzYXkodnNkYXRhKSkpICAgICAgICAgICAgICAgICAjQ2FsY3VsYXRlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnRzLg0Kc2FtcGxlRGlzdE1hdHJpeF9FdWNsaWRlYW4gPC0gYXMubWF0cml4KHNhbXBsZURpc3RzX0V1Y2xpZGVhbikgICNDb252ZXJ0IHRvIG1hdHJpeCBmb3JtYXQuDQpyb3duYW1lcyhzYW1wbGVEaXN0TWF0cml4X0V1Y2xpZGVhbikgPC0gcGFzdGUodnNkYXRhJGlkKSAgICAgICAgI0xhYmVsIFNhbXBsZSBuYW1lcy4NCmNvbG5hbWVzKHNhbXBsZURpc3RNYXRyaXhfRXVjbGlkZWFuKSA8LSBwYXN0ZSh2c2RhdGEkaWQpICAgICAgICAjTGFiZWwgU2FtcGxlIG5hbWVzLg0KY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwoOSwgIkJsdWVzIikpKSgyNTUpICAgICNDb2xvciBwYWxldHRlIHJhbmdlIGZvciBoZWF0bWFwIHZpc3VhbGl6YXRpb24uDQpTYW1wbGVEaXN0YW5jZXZpZ25ldHRlID0gcGhlYXRtYXAoc2FtcGxlRGlzdE1hdHJpeF9FdWNsaWRlYW4sICAgI0dlbmVyYXRlIGhlYXRtYXAgd2l0aCAnc2FtcGxlRGlzdE1hdHJpeCcgYW5kICdjb2xvcnMnIGlucHV0cy4NCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cz1zYW1wbGVEaXN0c19FdWNsaWRlYW4sICAgICAgICAjQ2x1c3RlcmluZyBieSBFdWNsaWRlYW4gZGlzdGFuY2UuDQogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHM9c2FtcGxlRGlzdHNfRXVjbGlkZWFuLCAgICAgICAgI0NsdXN0ZXJpbmcgYnkgRXVjbGlkZWFuIGRpc3RhbmNlLg0KICAgICAgICAgY29sPWNvbG9ycykNClNhbXBsZURpc3RhbmNldmlnbmV0dGUgI2dnc2F2ZSgiMkRfU0Quc3ZnIiwgU2FtcGxlRGlzdGFuY2V2aWduZXR0ZSwgZHBpID0gNjAwLCB3aWR0aCA9IDIuNTUsIGhlaWdodCA9IDIsIHVuaXRzID0gImluIiwgc2NhbGUgPSAyKQ0KYGBgDQo8YnI+DQo8YnI+DQpOZXh0LCBhICoqVm9sY2FubyBwbG90KiogY2FuIGJlIGFzc2VtYmxlZCB0byBwcm92aWRlIGEgZ2VuZXJhbCBvdmVydmlldyBvZiB0aGUgZ2VuZSBleHByZXNzaW9uIHByb2ZpbGVzIG9mIDJEIE5hdGl2ZSBoQVNDcyB2cyAyRCBHbHljb2VuZ2luZWVyZWQgaEFTQ3MuICoqVm9sY2FubyBwbG90cyoqIHByb3ZpZGUgYSBjbGVhciBhbmQgaW50dWl0aXZlIHZpc3VhbGl6YXRpb24gb2YgKipzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UqKiBhbmQgdGhlICoqZXh0ZW50IG9mIGZvbGQgY2hhbmdlcyoqIGZvciBldmVyeSBnZW5lIGRldGVjdGVkLiBIZXJlLCBlYWNoIGdlbmUgaXMgcGxvdHRlZCB3aXRoIHRoZWlyIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSAoYWRqdXN0ZWQgcC12YWx1ZXMgb24gdGhlIHktYXhpcykgYWdhaXNudCB0aGUgZm9sZCBjaGFuZ2UgKGxvZzIgZm9sZCBjaGFuZ2Ugb24gdGhlIHgtYXhpcykuIA0KDQpUaGVuLCBhICoqdGhyZXNob2xkKiogaXMgc2V0IHRvIGhpZ2hsaWdodCBnZW5lcyB0aGF0IGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgKCoqREVHcyoqKSwgYXMgcmVwcmVzZW50ZWQgaW4gdGhlIHBsb3QgaW4gdGhlIGZvcm0gb2YgZGFzaGVkIGxpbmVzLiBBcyBhZm9yZW1lbnRpb25lZCwgdGhpcyB3b3JrIGNvbnNpZGVycyBhcyAqKkRFR3MqKiBnZW5lcyB0aGF0IHByZXNlbnQgYW4gKiphZGp1c3RlZCBwLXZhbHVlIDwgMC4wNSoqIGFuZCAqKmxvZzIoZm9sZCBjaGFuZ2UpID4gMSoqIG9yICoqPCAtMSoqLiBUaGlzICoqY29tYmluYXRpb24gb2Ygc2lnbmlmaWNhbmNlIGFuZCBmb2xkIGNoYW5nZSoqIGluZm9ybWF0aW9uIGFsbG93cyByZXNlYXJjaGVycyB0byBlZmZpY2llbnRseSAqKmlkZW50aWZ5KiogYW5kICoqcHJpb3JpdGl6ZSoqICoqZ2VuZXMgb2YgaW50ZXJlc3QqKiBmb3IgZnVydGhlciBpbnZlc3RpZ2F0aW9uLiBJbiBhZGRpdGlvbiwgKipWb2xjYW5vIHBsb3RzKiogY2FuIGFsc28gYXNzaXN0IGluIHNjcmVlbmluZyBvdXQgZ2VuZXMgd2l0aCBoaWdoIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBidXQgbG93IGZvbGQgY2hhbmdlcywgd2hpY2ggbWF5IGJlIHNpZ25pZmljYW50IGR1ZSB0byBsYXJnZSBzYW1wbGUgc2l6ZXMgYnV0IG1heSBub3QgaGF2ZSBzdWJzdGFudGlhbCBiaW9sb2dpY2FsIHJlbGV2YW5jZS4NCg0KYGBge3IgMkQgVm9sY2FubyBwbG90LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KI091dHB1dCAyRCBWb2xjYW5vIHBsb3Qgd2l0aCBzcGVjaWZpYyBHZW5lcyBvZiBJbnRlcmVzdCBsYWJlbGxlZA0KDQpyZXNkZHNDUE0uZGYgPC0gYXMuZGF0YS5mcmFtZShyZXNkZHNDUE0pICAgICAgICAgICAgICAgICAgICAgICAgI0NvbnZlcnQgREVTZXEyIHJlc3VsdHMgb2JqZWN0IHRvIGEgZGF0YSBmcmFtZS4NCg0KI0NyZWF0ZSBjdXN0b20ga2V5LXZhbHVlIHBhaXJzIGZvciAnVXAnLCAnRG93bicsICdOb24tREVHJyBleHByZXNzaW9uLiBBY2hpZXZlZCB1c2luZyBuZXN0ZWQgJ2lmZWxzZScgc3RhdGVtZW50cy4NCmtleXZhbHMgPC0gIGlmZWxzZShyZXNkZHNDUE0kcGFkaiA+IDAuMDUsICdncmV5MzAnLCAgICAgICAgICAgICAjSWYgcGFkaiA+IDAuMDUgYXNzaWduIGdyZXkgY29sb3IuDQogICAgICAgICAgICBpZmVsc2UocmVzZGRzQ1BNJGxvZzJGb2xkQ2hhbmdlIDwgLTEsICdyb3lhbGJsdWUnLCAgI0lmIGxvZzJmb2xkY2hhbmdlIDwgLTEsIGFzc2lnbiBibHVlIGNvbG9yLg0KICAgICAgICAgICAgaWZlbHNlKHJlc2Rkc0NQTSRsb2cyRm9sZENoYW5nZSA+IDEsICdmaXJlYnJpY2szJywgICNJZiBsb2cyZm9sZGNoYW5nZSA+IDEsIGFzc2lnbiByZWQgY29sb3IuDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdncmV5MzAnKSkpICAgI090aGVyIHZhbHVlcyBhc3NpZ25lZCBncmV5IGNvbG9yLg0KI1JlbmFtZSBlbGVtZW50cyBpbiAna2V5dmFscycgdmVjdG9yOg0KbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSAnZmlyZWJyaWNrMyddIDwtICdVcCcgICAgICAgICAgICAgICAgICNBc3NpZ24gJ1VwJyB0byBlbGVtZW50cyBpbiByZWQuDQpuYW1lcyhrZXl2YWxzKVtrZXl2YWxzID09ICdncmV5MzAnXSA8LSAnTm9uLURFRycgICAgICAgICAgICAgICAgI0Fzc2lnbiAnTm9uLURFRycgdG8gZWxlbWVudHMgaW4gcmVkLg0KbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSAncm95YWxibHVlJ10gPC0gJ0Rvd24nICAgICAgICAgICAgICAgICNBc3NpZ24gJ1VwJyB0byBlbGVtZW50cyBpbiByZWQuDQoNCiNEZWZpbmUgdmVjdG9yIGNvbnRhaW5pbmcgR2VuZSBTeW1ib2xzIHRvIGhpZ2hsaWdodCBpbiBwbG90DQpzZWxlY3RlZCA9IGMoIlBUR1MyIiwgIktSVDE5IiwgIkNYQ0wxIiwgIlNMQzdBMTEiLCAiTkRORiIsICJQR0QiLCAiVkNBTTEiLCAiR1BDMSIsICJBTkdQVDEiLCAiR0RGMTUiKQ0KDQojVm9sY2FubyBwbG90IHNldHRpbmdzDQplbmh2b2xjIDwtIEVuaGFuY2VkVm9sY2FubyhyZXNkZHNDUE0uZGYsICAgICAgICAgICAgICAgICAgICAgICAgI0NyZWF0ZSBWb2xjYW5vIHBsb3QgdXNpbmcgJ3Jlc2Rkc0NQTS5kZicNCiAgICAgICAgeCA9ICJsb2cyRm9sZENoYW5nZSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQ29sdW1uIG5hbWUgY29udGFpbmluZyBsb2cyKGZvbGQgY2hhbmdlKSB2YWx1ZXMuDQogICAgICAgIHkgPSAicGFkaiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0NvbHVtbiBuYW1lIGNvbnRhaW5pbmcgYWRqdXN0ZWQgcC12YWx1ZSB2YWx1ZXMuDQogICAgICAgICNsYWIgPSBOQSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1VuY29tbWVudCB0aGlzIGZ1bmN0aW9uIGZvciB1bmxhYmVsZWQgZ2VuZXMuDQogICAgICAgIHBDdXRvZmYgPSAwLjA1LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0N1dC1vZmYgdGhyZXNob2xkIGZvciBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UuDQogICAgICAgIEZDY3V0b2ZmID0gMSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0N1dC1vZmYgdGhyZXNob2xkIGZvciBhYnNvbHV0ZSBsb2cyKGZvbGQgY2hhbmdlKS4NCiAgICAgICAgdGl0bGUgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjUGxvdCB0aXRsZS4NCiAgICAgICAgc3VidGl0bGUgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjUGxvdCBzdWJ0aXRsZS4NCiAgICAgICAgY2FwdGlvbiA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjUGxvdCBjYXB0aW9uLg0KICAgICAgICB4bGFiID0gYnF1b3RlKH5Mb2dbMl1+IihGb2xkIENoYW5nZSkiKSwgICAgICAgICAgICAgICAgICNMYWJlbCBmb3IgeC1heGlzLiANCiAgICAgICAgeWxhYiA9IGJxdW90ZSh+LUxvZ1sxMF0gfiAiKCIgKiBpdGFsaWMoUFthZGpdKSAqICIpIiksICAjTGFiZWwgZm9yIHktYXhpcy4NCiAgICAgICAgY29sQWxwaGEgPSAwLjUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQWxwaGEgZm9yIGNvbG9yIHRyYW5zcGFyZW5jeS4NCiAgICAgICAgY29sQ3VzdG9tID0ga2V5dmFscywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjT3ZlcnJpZGUgY29sb3Igc2NoZW1lIChlLmcuIGNvbG9yIGJ5IHBhdGh3YXksIGNlbGwtdHlwZSBvciBjb25kaXRpb24pLg0KICAgICAgICBwb2ludFNpemUgPSAxLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTaXplIG9mIHBsb3R0ZWQgcG9pbnRzLg0KICAgICAgICBsYWJTaXplID0gNCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTaXplIG9mIGxhYmVscyBmb3IgZWFjaCBwb2ludC4NCiAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQ29ubmVjdCBsYWJlbHMgdG8gZWFjaCBjb3JyZXNwb25kaW5nIHBvaW50IGJ5IGxpbmUgY29ubmVjdG9ycy4NCiAgICAgICAgd2lkdGhDb25uZWN0b3JzID0gMC42NSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTGluZSB3aWR0aCBvZiBjb25uZWN0b3JzLg0KICAgICAgICBhcnJvd2hlYWRzID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNEcmF3IGFycm93aGVhZHMgaW5zdGVhZCBvZiBzaW1wbGUgbGluZSBjb25uZWN0b3JzLg0KICAgICAgICBib3hlZExhYmVscyA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNEcmF3IGxhYmVscyB3aXRoaW4gYm94ZXMuDQogICAgICAgIGRpcmVjdGlvbkNvbm5lY3RvcnMgPSAnYm90aCcsICAgICAgICAgICAgICAgICAgICAgICAgICAgI0RpcmVjdGlvbiB0byBkcmF3IGNvbm5lY3RvcnMgKGUuZy4sICd5JywgJ3gnIG9yICdib3RoJykuDQogICAgICAgIHhsaW0gPSBjKC02LCA2KSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xpbWl0cyBvZiB4LWF4aXMuDQogICAgICAgIHlsaW0gPSBjKDAsIC1sb2cxMCgxMGUtMjU1KSksICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xpbWl0cyBvZiB5LWF4aXMuDQojRXhjbHVkZSB0aGVzZSBpZiBub3QgaGlnaGxpZ2h0aW5nIHNwZWNpZmljIGdlbmVzDQogICAgICAgIGxhYiA9IHJlc2Rkc0NQTS5kZiRnZW5lSUQsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0lucHV0IEdlbmUgU3ltYm9sIGNvbHVtbiBvZiBkYXRhLmZyYW1lIG9iamVjdC4NCiAgICAgICAgc2VsZWN0TGFiID0gc2VsZWN0ZWQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjVmVjdG9yIGNvbnRhaW5pbmcgYSBzdWJzZXQgb2YgZ2VuZXMgb2YgaW50ZXJlc3QuDQogICAgICAgICkNCg0KI0N1c3RvbWl6ZSBheGlzIGxpbWl0cyBhbmQgYnJlYWtzDQpwMSA8LSAgZW5odm9sYyArDQogICAgZ2dwbG90Mjo6Y29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC02LjQsIDYuNCksICAgICAgICAgICAgICAgI1pvb20gcGxvdCB0byB0aGUgc3BlY2lmaWMgeC1heGlzIGxpbWl0LiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxpbSA9IGMoMCwgMjUwKSkgKyAgICAgICAgICAgICAgICAjWm9vbSBwbG90IHRvIHRoZSBzcGVjaWZpYyB5LWF4aXMgbGltaXQuIA0KICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKC02LCA2LCAyKSkgKyAgICAgICAgICNTZXQgc3BhY2luZyBvZiBicmVha3MgaW4gcGxvdCB4LWF4aXMuDQogICAgZ2dwbG90Mjo6c2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgMjUwLCA1MCkpICAgICAgICAgI1NldCBzcGFjaW5nIG9mIGJyZWFrcyBpbiBwbG90IHktYXhpcy4NCnAxDQpnZ3NhdmUoIjJEX1ZvbGNhbm9fV2lkZV9MYWJlbC5zdmciLCBwMSwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDIuOCwgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpDQpgYGANCjxicj4NCkFsdGVybmF0aXZlbHksICoqVm9sY2FubyBwbG90cyoqIGNhbiBiZSBjdXN0b21pemVkIHZpYSBvdGhlciBwYWNrYWdlcyAoZS5nLiwgKidnZ3Bsb3QyJyopIGFzIHN1YnBsb3Qgb3ZlcmxheXMgZm9yIHByZXNlbnRpbmcgYSBsaXN0IG9mIHRhcmdldCBnZW5lcyB3aXRoIGRpZmZlcmVudCBzaGFkaW5nIHNwZWNpZmljYXRpb25zLg0KDQpGb3IgaW5zdGFuY2UsICoqb3ZlcmxheWluZyoqIGFsbCBnZW5lcyB0aGF0ICoqbWF0Y2ggYSBzcGVjaWZpYyByZXF1aXJlbWVudCoqIChpLmUuLCBhbGwgSUxzIGdlbmVzKS4NCg0KYGBge3IgZ2dwbG90MiBWb2xjYW5vLCBpbmNsdWRlPUZBTFNFLCBlY2hvPUZBTFNFfQ0KI0FsdGVybmF0aXZlIFZvbGNhbm8gcGxvdCBmbGV4aWJpbGl0eSB0aHJvdWdoICdnZ3Bsb3QyJyBwYWNrYWdlLiBOb3RlOiBkb2Vzbid0IGhhdmUgRW5oYW5jZWRWb2xjYW5vIGZsZXhpYmlsaXR5IGZvciBjb3JyZWN0aW5nIHAtdmFsdWVzID0gMC4NCg0KcmVzZGRzQ1BNVk9MQy5kZiA8LSByZXNkZHNDUE0uZGYNCiNBZGQgYSBjb2x1bW4gdG8gdGhlIGRhdGEgZnJhbWUgdG8gc3BlY2lmeSBpZiBnZW5lcyBhcmUgVVAtIG9yIERPV04tIHJlZ3VsYXRlZCBERUdzDQpyZXNkZHNDUE1WT0xDLmRmJGRpZmZleHByZXNzZWQgPC0gIk5vbi1ERUciDQojVVBSRUdVTEFURUQgREVHcw0KcmVzZGRzQ1BNVk9MQy5kZiRkaWZmZXhwcmVzc2VkW3Jlc2Rkc0NQTVZPTEMuZGYkbG9nMkZvbGRDaGFuZ2UgPiAxICYgcmVzZGRzQ1BNVk9MQy5kZiRwYWRqIDwgMC4wNV0gPC0gIlVwcmVndWxhdGVkIg0KI0RPV05SRUdVTEFURUQgREVHcw0KcmVzZGRzQ1BNVk9MQy5kZiRkaWZmZXhwcmVzc2VkW3Jlc2Rkc0NQTVZPTEMuZGYkbG9nMkZvbGRDaGFuZ2UgPCAtMSAmIHJlc2Rkc0NQTVZPTEMuZGYkcGFkaiA8IDAuMDVdIDwtICJEb3ducmVndWxhdGVkIg0KDQojVm9sY2FubyAnZ2dwbG90MicgdGhlbWUNCnZvbGNfdGhlbWUgPC0gdGhlbWVfc2V0KHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjApICsNCiAgICAgICAgICAgIHRoZW1lKA0KICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgbWFyZ2luID0gbWFyZ2luKDAsMTAsMCwwKSwgc2l6ZSA9IDE1LCBjb2xvciA9ICdibGFjaycpLA0KICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIG1hcmdpbiA9IG1hcmdpbigxMCwwLDAsMCksIHNpemUgPSAxNSwgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkNCiAgICAgICAgICAgICkpDQoNCmdncGxvdChkYXRhID0gcmVzZGRzQ1BNVk9MQy5kZiwNCiAgICAgICBhZXMoeCA9IGxvZzJGb2xkQ2hhbmdlLA0KICAgICAgICAgICB5ID0gLWxvZzEwKHBhZGopLA0KICAgICAgIGNvbCA9IGRpZmZleHByZXNzZWQpKSArDQogICAgICAgZ2VvbV9wb2ludChzaXplID0gMSkgKyANCiAgICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSwgY29sID0gJ2dyZXkzMCcsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC1sb2cxMCgwLjA1KSksIGNvbCA9ICdncmV5MzAnLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInJveWFsYmx1ZSIsICJncmV5MzAiLCAiZmlyZWJyaWNrMyIpLCAjU2V0IGNvbG9yIHZlY3RvcnMgZm9yIGdlbmUgY2xhc3NpZmljYXRpb25zDQogICAgICAgICAgIGxhYmVscyA9IGMoIkRvd25yZWd1bGF0ZWQiLCAiTm9uLURFR3MiLCAiVXByZWd1bGF0ZWQiKSkgKyAjU2V0IGxhYmVsIG5hbWVzIHRvIG92ZXJ3cml0ZSB0ZXh0IGluIGRhdGEuZnJhbWUgKFVQLCBET1dOLCBOTykNCiAgICAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMzAwKSwgeGxpbSA9IGMoLTExLCAxMSkpICsgI1NldCBsaW1pdHMgZHVlIHRvIHBhZGogPSAwIG9uIHNvbWUgZ2VuZXMsIHRoZXkgd2lsbCBzdGlsbCBiZSBwbG90dGVkIGJ1dCBjb2xsYXBzZWQgb24gZWRnZQ0KICAgICAgIGxhYnMoY29sb3IgPSAnTGVnZW5kJywgI0xlZ2VuZCB0aXRsZSwgDQogICAgICAgICAgIHggPSBleHByZXNzaW9uKCJMb2ciWzJdKiIoRm9sZCBDaGFuZ2UpIiksDQogICAgICAgICAgIHkgPSBleHByZXNzaW9uKCItTG9nIlsxMF0qUFthZGpdKSkgKyANCiAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoc2VxKC0xMCwgMTAsIDUpKSwgI0N1c3RvbWl6ZSB4LWF4aXMgdGlja3MNCiAgICAgICAgICAgbGltaXRzID0gYygtMjAsIDIwKSkgKyAjU2hvdyBkYXRhcG9pbnRzIHdpdGhpbiB0aGlzIHJlZ2lvbg0Kdm9sY190aGVtZQ0KYGBgDQoNCmBgYHtyIGdncGxvdDIgVm9sY2FubyBzZXR0aW5ncywgaW5jbHVkZT1GQUxTRX0NCnJlc2Rkc0NQTVZPTEMuZGYgJT4lDQogIGRpc3RpbmN0KGRpZmZleHByZXNzZWQpICU+JQ0KICBwdWxsKCkgIA0KIyAiTk8iICAiVVAiICAiRE9XTiINCg0KY29scyA8LSBjKCJEb3ducmVndWxhdGVkIiA9ICJyb3lhbGJsdWUiLCAiVXByZWd1bGF0ZWQiID0gImZpcmVicmljazMiLCAiTm9uLURFRyIgPSAiZ3JleTMwIikgDQpzaXplcyA8LSBjKCJEb3ducmVndWxhdGVkIiA9IDEsICJVcHJlZ3VsYXRlZCIgPSAxLCAiTm9uLURFRyIgPSAxKSANCmFscGhhcyA8LSBjKCJEb3ducmVndWxhdGVkIiA9IDAuNSwgIlVwcmVndWxhdGVkIiA9IDAuNSwgIk5vbi1ERUciID0gMC41KQ0KIyAiI2ZmYWQ3MyIsICJkb3duIiA9ICIjMjZiM2ZmIg0KDQpnZ3Bsb3RWb2xjIDwtIGdncGxvdChkYXRhID0gcmVzZGRzQ1BNVk9MQy5kZiwgYWVzKHggPSBsb2cyRm9sZENoYW5nZSwgeSA9IC1sb2cxMChwYWRqKSwNCiAgZmlsbCA9IGRpZmZleHByZXNzZWQsDQogIHNpemUgPSBkaWZmZXhwcmVzc2VkLA0KICBhbHBoYSA9IGRpZmZleHByZXNzZWQpKSArDQogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSArIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSwgY29sID0gJ2dyZXkzMCcsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygtbG9nMTAoMC4wNSkpLCBjb2wgPSAnZ3JleTMwJywgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArICMgTW9kaWZ5IHBvaW50IGNvbG9yDQogIHNjYWxlX3NpemVfbWFudWFsKHZhbHVlcyA9IHNpemVzKSArICMgTW9kaWZ5IHBvaW50IHNpemUNCiAgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcyA9IGFscGhhcykgKyAjIE1vZGlmeSBwb2ludCB0cmFuc3BhcmVuY3kNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoc2VxKC0xMCwgMTAsIDUpKSwgICAgICAgDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xMCwgMTApKSArDQogIGxhYnMoY29sb3IgPSAnTGVnZW5kJywgI2xlZ2VuZF90aXRsZSwgDQogICAgICAgeCA9IGV4cHJlc3Npb24oImxvZyJbMl0qIkZvbGQgQ2hhbmdlIiksIHkgPSBleHByZXNzaW9uKCItbG9nIlsxMF0qUFthZGpdKSkNCg0KZ2dwbG90Vm9sYw0KI2dnc2F2ZSgiMkR2czNEX2dncGxvdFZvbGMuc3ZnIiwgZ2dwbG90Vm9sYywgd2lkdGggPSAzLjgsIGhlaWdodCA9IDIuNSwgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpDQpgYGANCg0KYGBge3IgR0dQTE9UIFZvbGNhbm8gT3ZlcmxheSBhbmQgU3BlY2lmaWMgTGFiZWxpbmcgMiwgZWNobz1GQUxTRX0NCiMtLS0tLS0tLS0tLS0tLU9WRVJMQVkgVEFSR0VUIEdFTkVTIE9OIEdSRVlFRCBPVVQgVk9MQ0FOTyBQTE9UUy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEFkZCBzdWJwbG90IGxheWVyIHRvIHRoZSBtYWluIHZvbGNhbm8gcGxvdCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KaWxzIDwtIHN0cl9zdWJzZXQocmVzZGRzQ1BNVk9MQy5kZiRnZW5lSUQsICJeSUwiKSAjIl4oSXxMKXsyfVswLTldKyQiKSAgI1RoaXMgZmV0Y2hlcyBnZW5lIHN5bWJvbHMgc3RhcnRpbmcgd2l0aCBJTCBpbiB0aGUgbmFtZS4NCiNsZW5ndGgoaWxzKSAjNTINCg0KaWxfZ2VuZXMgPC0gcmVzZGRzQ1BNVk9MQy5kZiAlPiUNCiAgZmlsdGVyKGdlbmVJRCAlaW4lIGlscykNCg0KZ2dwbG90Vm9sY19zdWJsYXllciA8LSBnZ3Bsb3QoZGF0YSA9IHJlc2Rkc0NQTVZPTEMuZGYsICMgT3JpZ2luYWwgZGF0YSAgDQogICAgICAgYWVzKHggPSBsb2cyRm9sZENoYW5nZSwgeSA9IC1sb2cxMChwYWRqKSkpICsgDQogIGdlb21fcG9pbnQoY29sb3VyID0gImdyZXkiLCBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3BvaW50KGRhdGEgPSBpbF9nZW5lcywgIyBOZXcgbGF5ZXIgY29udGFpbmluZyBkYXRhIHN1YnNldCBpbF9nZW5lcyAgICAgICANCiAgICAgICAgICAgICBzaXplID0gMiwNCiAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgIGZpbGwgPSAiZmlyZWJyaWNrIiwNCiAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTEsIDEpLCBjb2wgPSAnZ3JleTMwJywgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC1sb2cxMCgwLjA1KSksIGNvbCA9ICdncmV5MzAnLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogIGxhYnMoY29sb3IgPSAnTGVnZW5kJywgI2xlZ2VuZF90aXRsZSwgDQogICAgICAgeCA9IGV4cHJlc3Npb24oImxvZyJbMl0qIihGb2xkIENoYW5nZSkiKSwgeSA9IGV4cHJlc3Npb24oIi1sb2ciWzEwXSpQW2Fkal0pKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYyhzZXEoLTEwLCAxMCwgNSkpLCAjQ3VzdG9taXplIFggYXhpcyB0aWNrcw0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMTAsIDEwKSkgKyAjIFNob3cgZGF0YXBvaW50cyB3aXRoaW4gdGhpcyByZWdpb24NCiAgdm9sY190aGVtZQ0KDQpnZ3Bsb3RWb2xjX3N1YmxheWVyDQojZ2dzYXZlKCIyRF9nZ3Bsb3RWb2xjX3N1Yi5zdmciLCBnZ3Bsb3RWb2xjX3N1YmxheWVyLCB3aWR0aCA9IDMuOCwgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpDQpgYGANCjxicj4NCkluIGFkZGl0aW9uLCBpdCBpcyBhbHNvIHBvc3NpYmxlIHRvIGFzc2VtYmxlIGEgKipWb2xjYW5vIHBsb3QqKiBjb250YWluaW5nIGFuICoqb3ZlcmxheSoqIG9mIGdlbmVzIG9mIGludGVyZXN0IG9uIHRvcC4NCg0KIVtdKFRyZWF0ZWQvMkR2czNEX2dncGxvdFZvbGNfbGFiZWxzLnN2ZykNCg0KYGBge3IgR0dQTE9UIFZvbGNhbm8gT3ZlcmxheSBhbmQgU3BlY2lmaWMgTGFiZWxpbmcgMywgaW5jbHVkZT1GQUxTRX0NCiMtLS0tLS0tLS0tLS0tLS0tLU9WRVJMQVkgTEFCRUxFRCBHRU5FUy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KU2VsZWN0ZWRfZ2VuZXMgPC0gcmVzZGRzQ1BNVk9MQy5kZiAlPiUNCiAgZmlsdGVyKGdlbmVJRCAlaW4lIGMoIklMMzIiLCAiSUwzNCIsICJJTDFCIiwgIkNPTDdBMSIsICJDT0wxMEExIiwgIk1NUDEzIiwgIkxBTUMyIiwgIkxBTUIzIiwgIkNPTDI0QTEiLCAiTEFNQTEiLCAiVklUIikpDQpVUF9TZWxlY3RlZF9nZW5lcyA8LSByZXNkZHNDUE1WT0xDLmRmICU+JQ0KICBmaWx0ZXIoZ2VuZUlEICVpbiUgYygiSUwzMiIsICJJTDM0IiwgIklMMUIiLCAiQ09MN0ExIiwgIkNPTDEwQTEiLCAiTU1QMTMiLCAiTEFNQzIiLCAiTEFNQjMiKSkNCkRPV05fU2VsZWN0ZWRfZ2VuZXMgPC0gcmVzZGRzQ1BNVk9MQy5kZiAlPiUNCiAgZmlsdGVyKGdlbmVJRCAlaW4lIGMoIkNPTDI0QTEiLCAiTEFNQTEiLCAiVklUIikpDQoNCmdncGxvdFZvbGNfbGFiZWxzIDwtIGdncGxvdChkYXRhID0gcmVzZGRzQ1BNVk9MQy5kZiwNCiAgICAgICBhZXMoeCA9IGxvZzJGb2xkQ2hhbmdlLCB5ID0gLWxvZzEwKHBhZGopKSkgKyANCiAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBkaWZmZXhwcmVzc2VkKSwgDQogICAgICAgICAgICAgYWxwaGEgPSAwLjIsIA0KICAgICAgICAgICAgIHNoYXBlID0gMTYsDQogICAgICAgICAgICAgc2l6ZSA9IDEpICsgDQogIGdlb21fcG9pbnQoZGF0YSA9IFVQX1NlbGVjdGVkX2dlbmVzLA0KICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgc2l6ZSA9IDIsIA0KICAgICAgICAgICAgIGZpbGwgPSAic3RlZWxibHVlIiwgDQogICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIikgKyANCiAgZ2VvbV9wb2ludChkYXRhID0gRE9XTl9TZWxlY3RlZF9nZW5lcywNCiAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgIHNpemUgPSAyLCANCiAgICAgICAgICAgICBmaWxsID0gImZpcmVicmljazMiLCANCiAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSArIA0KICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsgDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMobG9nMigwLjUpLCBsb2cyKDIpKSwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IFNlbGVjdGVkX2dlbmVzLCAjIEFkZCBsYWJlbHMgbGFzdCB0byBhcHBlYXIgYXMgdGhlIHRvcCBsYXllciAgDQogICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gZ2VuZUlEKSwNCiAgICAgICAgICAgICAgICAgICBmb3JjZSA9IDIsDQogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDMsDQogICAgICAgICAgICAgICAgICAgI2RpcmVjdGlvbiA9ICJ5IiwNCiAgICAgICAgICAgICAgICAgICBzaXplID0gMiwNCiAgICAgICAgICAgICAgICAgICBtaW4uc2VnbWVudC5sZW5ndGggPSB1bml0KDAsICJsaW5lcyIpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMiwgImxpbmVzIikpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYyhzZXEoLTEwLCAxMCwgMikpLCAgICAgDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xMCwgMTApKSArDQogIHZvbGNfdGhlbWUNCg0KZ2dwbG90Vm9sY19sYWJlbHMNCiNnZ3NhdmUoIjJEdnMzRF9nZ3Bsb3RWb2xjX2xhYmVscy5zdmciLCBnZ3Bsb3RWb2xjX2xhYmVscywgd2lkdGggPSAzLjgsIGhlaWdodCA9IDIuNSwgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpDQpgYGANCg0KPGJyPg0KQWx0ZXJuYXRpdmVseSwgaXQgaXMgcG9zc2libGUgdG8gYXNzZW1ibGUgYSAqKk1BIHBsb3QqKiwgd2hpY2ggY29udmV5cyBhIHNpbWlsYXIgb3ZlcnZpZXcgdG8gKipWb2xjYW5vIHBsb3RzKiouIEhvd2V2ZXIsIHRoaXMgcGxvdCBsYWNrcyB0aGUgZGVzaWduIGZsZXhpYmlsaXR5IHRoYXQgVm9sY2FubyBwbG90cyBvZmZlciB0aHJvdWdoIHRoZWlyIGRlZGljYXRlZCBSIHBhY2thZ2VzLg0KDQpgYGB7ciBBbHRlcm5hdGl2ZSAyRCBNQSBQTE9UfQ0KI0FsdGVybmF0aXZlIHRvIFZvbGNhbm8gLSBNQSBQbG90LiBMZXNzIGZsZXhpYmlsaXR5IGluIGN1c3RvbWl6aW5nIHRoZSBmaW5hbCBmaWd1cmUuDQpNQVBsb3RfZGRzIDwtIERFU2VxMjo6cGxvdE1BKHJlc2Rkc0NQTSwgYWxwaGEgPSAwLjA1LCAjU2V0IHAtdmFsdWUgY3V0LW9mZiB0aHJlc2hvbGQuDQogICAgICAgICAgICAgICBjb2xOb25TaWcgPSAiZ3JheTMwIiwgICAgICAgICAgICAgICAgICAjU2V0IGNvbG9yIGNvZGUgZm9yIE5vbi1ERUcuDQogICAgICAgICAgICAgICBjb2xTaWcgPSAicm95YWxibHVlMyIsICAgICAgICAgICAgICAgICAjU2V0IGNvbG9yIGNvZGUgZm9yIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuDQogICAgICAgICAgICAgICB5bGltID0gYygtNywgNykpICAgICAgICAgICAgICAgICAgICAgICAjU2V0IHktYXhpcyBsaW1pdC4NCmFibGluZShoID0gYygxLCAtMSksIGx0eSA9IDIpICAgICAgICAgICAgICAgICAgICAgICAgICNEcmF3IGhvcml6b250YWwgbGluZXMgYXQgdGhlIHNwZWNpZmllZCB5LWF4aXMgdmFsdWVzLCBsaW5lIHR5cGUgLSBkYXNoZWQuDQpgYGANCjxicj4NCkFwYXJ0IGZyb20gKipWb2xjYW5vIHBsb3RzKiosICoqSGVhdG1hcHMqKiBwcm92aWRlIGFuIGltcG9ydGFudCB2aXN1YWxpemF0aW9uIHRvb2wgaW4gUk5BU2VxIGZvciBkZXRlY3RpbmcgZ2VuZSBleHByZXNzaW9uIHRyZW5kcyBhbmQgaGlnaGxpZ2h0aW5nIGdlbmVzIHdpdGggcmVsZXZhbnQgYmlvbG9naWNhbCBmdW5jdGlvbnMuIEhlcmVpbiwgZWFjaCBzYW1wbGUgaXMgYXNzaWduZWQgdG8gYSBjb2x1bW4sIGFuZCBlYWNoIHJvdyBjb3JyZXNwb25kcyB0byBhICoqREVHKiogd2l0aCAqKmNvbG9yLWNvZGVkIGV4cHJlc3Npb24gbGV2ZWwqKi4gRXhwcmVzc2lvbiB2YWx1ZXMgYXJlIHR5cGljYWxseSBub3JtYWxpemVkIGFuZCB0cmFuc2Zvcm1lZCAoaS5lLiwgKipyb3cgei1zY2FsaW5nKiopIHRvIGVuc3VyZSB0aGF0IGdlbmVzIHdpdGggdmFyeWluZyBleHByZXNzaW9uIGxldmVscyBjYW4gYmUgY29tcGFyZWQgZWFzaWx5LiAqKkhlYXRtYXBzKiogYXJlIHVzdWFsbHkgcGFpcmVkIHdpdGggKipoaWVyYXJjaGljYWwgY2x1c3RlcmluZyoqIGFsZ29yaXRobXMgKGUuZy4sIFBlYXJzb24ncykgdGhhdCBncm91cCB0b2dldGhlciBnZW5lcyBhbmQgc2FtcGxlcyB3aXRoIHNpbWlsYXIgZXhwcmVzc2lvbiBwcm9maWxlcywgZ2VuZXJhdGluZyBhIGhpZXJhcmNoaWNhbCB0cmVlLWxpa2UgZGVuZHJvZ3JhbS4gKipIZWF0bWFwcyoqIGFyZSB0aHVzIHVzZWZ1bCBpbiBSTkFTZXEgZG93bnN0cmVhbSBhbmFseXNpcyBmb3IgcmV2ZWFsaW5nICoqY28tZXhwcmVzc2lvbiBwYXR0ZXJucyoqIGFuZCAqKmJpb2xvZ2ljYWwgZnVuY3Rpb25zKiogYWZmZWN0ZWQgYnkgZXhwZXJpbWVudGFsIGNvbmRpdGlvbnMuDQoNCg0KYGBge3IgSGVhdG1hcCBzZXR1cCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNUcmFuc2Zvcm1hdGlvbiBvZiBkYXRhIGZvciBIZWF0bWFwDQp2c2RhdGEgPC0gdnN0KGRkc0NQTSwgYmxpbmQgPSBGQUxTRSkgICAgICAgICNBcHBseSB2YXJpYW5jZS1zdGFiaWxpemluZyB0cmFuc2Zvcm1hdGlvbi4NCnZzdF9tYXQgPC0gYXNzYXkodnNkYXRhKSAgICAgICAgICAgICAgICAgICAgI0NyZWF0ZSBtYXRyaXggd2l0aCB0cmFuc2Zvcm1lZCBnZW5lIGV4cHJlc3Npb24gdmFsdWVzLg0KdnN0X21hdCA8LSB2c3RfbWF0W3Jvd25hbWVzKHNpZ3NBTEwuZGYpLCBdICAjU3Vic2V0IG1hdHJpeCB0byBpbmNsdWRlIG9ubHkgREVHUywgaS5lLiwgcm93cyB0aGF0IG1hdGNoIGdlbmVzIGxpc3RlZCBpbiAnc2lnc0FMTC5kZicuDQpHZW5lbmFtZSA8LSBtYXBJZHMob3JnLkhzLmVnLmRiLCAgICAgICAgICAgICNNYXAgRW5zZW1ibCBJRCBmcm9tIG1hdHJpeCB0byBHZW5lIFN5bWJvbCBhbmQgc3RvcmUgaW4gdmFyaWFibGUgJ0dlbmVuYW1lJy4NCiAgICAgICAgICAgICAgIGtleXMgPSByb3cubmFtZXModnN0X21hdCksDQogICAgICAgICAgICAgIGtleXR5cGUgPSAiRU5TRU1CTCIsDQogICAgICAgICAgICAgIGNvbHVtbiA9ICJTWU1CT0wiKQ0KDQojUmVwbGFjZSBOQSBnZW5lIHN5bWJvbHMgd2l0aCBFTlNFTUJMIElEcyBpbiB2c3RfbWF0Lg0KIyhpKSBJZGVudGlmeSB3aGljaCBlbnRyaWVzIGluICdHZW5lbmFtZScgaGF2ZSBtaXNzaW5nIHZhbHVlcyAoTkEpLg0Kbm9fc3ltYm9sX2lkeCA8LSBpcy5uYShHZW5lbmFtZSkNCg0KIyhpaSkgRm9yICdHZW5lbmFtZScgZW50cmllcyB3aXRoIE5BLCByZXBsYWNlIHZhbHVlcyB3aXRoIG9yaWdpbmFsIEVuc2VtYmwgSUQgZXh0cmFjdGVkIGZyb20gJ3ZzdF9tYXQnIHJvdyBuYW1lcy4NCkdlbmVuYW1lW25vX3N5bWJvbF9pZHhdIDwtIHJvdy5uYW1lcyh2c3RfbWF0KVtub19zeW1ib2xfaWR4XQ0KDQojKGlpaSkgQ29udmVydCAnR2VuZW5hbWUnIHZlY3RvciBpbnRvIGEgc2luZ2xlIGNvbHVtbiBkYXRhLmZyYW1lLCBtYWtpbmcgaXQgc3VpdGFibGUgZm9yIGFzc2lnbm1lbnQgdG8gcm93IG5hbWVzIG9mICd2c3RfbWF0Jw0KRU5TX2dlbmVJRHMgPC0gc3RhY2soR2VuZW5hbWUpICAgICAgIA0KDQojKGl2KSBSZXBsYWNlIEVuc2VtYmwgSUQgZW50cmllcyB3aXRoIEdlbmUgU3ltYm9scyB3aGVuIGF2YWlsYWJsZSwgYW5kIHJldGFpbnMgb3JpZ2luYWwgRW5zZW1ibCBJRCBpZiBOQS4NCnJvdy5uYW1lcyh2c3RfbWF0KSA8LSBFTlNfZ2VuZUlEcyR2YWx1ZXMgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KI0RvdWJsZS1jaGVjayB0aGF0IG5vIERFR3Mgd2VyZSBsb3N0IGR1cmluZyBhc3NpZ25tZW50DQojZGltKHZzdF9tYXQpICM1NjggREVHcyAtPiBUUlVFDQoNCiNTY2FsZSBnZW5lcyB6LXNjb3JlIGJ5IHJvdywgYXMgb3RoZXJ3aXNlIGxhcmdlIHZhbHVlcyBmcm9tIGhpZ2hseSBleHByZXNzZWQgZ2VuZXMgd291bGQgZG9taW5hdGUgdGhlIHBsb3QNCnZzdF9tYXRfeiA8LSB0KHNjYWxlKHQodnN0X21hdCkpKQ0KDQojQXNzaWduIGNvbHVtbiBuYW1lcyB0byBlYWNoIHNhbXBsZQ0KY29sbmFtZXModnN0X21hdF96KSA8LSBjKCIyREMxIiwgIjJEQzIiLCAiMkRDMyIsICIyREM0IiwgIjJEQzUiLCAiMkRHMSIsICIyREcyIiwgIjJERzMiLCAiMkRHNCIsICIyREc1IikNCg0KI0hlYXRtYXAgcGFyYW1ldGVycw0KY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCAgICAgICAgICAgICAgICAgICAgICAgICNDcmVhdGUgc2VnbWVudHMgZm9yIHRoZSBjb2xvciBncmFkaWVudC4NCiAgICAgICAgICAgICAgICBjKCIjMjE2NkFDIiwgIndoaXRlIiwgIiNCMjE4MkIiKSkgICAjQ3JlYXRlIGNvbG9yIGdyYWRpZW50IHdpdGggdGhlIHNwZWNpZmllZCBjb2xvciBjb2Rlcy4NCg0KbGdkX2xpc3QgPC0gbGlzdCh0aXRsZSA9ICJaLXNjb3JlIiwgICAgICAgICAgICAgICAgICAgICAgICNTZXQgbGVnZW5kIHRpdGxlLg0KICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDIuNSwgImNtIiksICAgICAgICAgICNTZXQgaGVpZ2h0IG9mIHRoZSBsZWdlbmQgYm9keS4NCiAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCgwLjQsICJjbSIpLCAgICAgICAgICAgICAjU2V0IHdpZHRoIG9mIGVhY2ggbGVnZW5kIGdyaWQuDQogICAgICAgICAgICAgICAgdGl0bGVfcG9zaXRpb24gPSAidG9wY2VudGVyIiwgICAgICAgICAgICAgI1NldCBwb3NpdGlvbiBvZiB0aGUgdGl0bGUuDQogICAgICAgICAgICAgICAgZ2FwID0gdW5pdCg0LCAibW0iKSkgICAgICAgICAgICAgICAgICAgICAgI1NldCBnYXAgYmV0d2VlbiBoZWF0bWFwIGFuZCBsZWdlbmQuDQpgYGANCg0KDQpgYGB7ciBPdXRwdXQgSGVhdG1hcCwgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJ30NCiNPdXRwdXQgZnVsbCBERUdzIEhlYXRtYXANCmh0IDwtIEhlYXRtYXAodnN0X21hdF96LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTWF0cml4IGlucHV0IGZvciBoZWF0bWFwLg0KICAgICAgICBjb2wgPSBjb2xfZnVuLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgdmVjdG9yIG9mIGNvbG9ycyBmb3IgaW50ZXJwb2xhdGlvbi4NCiAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBzaG93IGNvbHVtbiBsYWJlbGluZy4gDQogICAgICAgIHNob3dfcm93X25hbWVzID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgdG8gc2hvdyByb3cgbGFiZWxpbmcuDQogICAgICAgICNyb3dfbGFiZWxzID0gc2lncy5kZltyb3duYW1lcyh2c3RfbWF0X3opLF0kU3ltYm9sLCAgICAgI1VuY29tbWVudCB0byBzcGVjaWZ5IHJvdyBsYWJlbGluZy4gDQogICAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwgICAgICAgICAgICAgICAgICAgICAgI1NldCBmb250IHNpemUgZm9yIHJvdyBsYWJlbGluZy4NCiAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2x1bW5zID0gInBlYXJzb24iLCAgICAgICAgICAgICAgICAjU2V0IGNsdXN0ZXJpbmcgbWV0aG9kIGZvciBjb2x1bW4gZGVuZHJvZ3JhbS4NCiAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gInBlYXJzb24iLCAgICAgICAgICAgICAgICAgICAjU2V0IGNsdXN0ZXJpbmcgbWV0aG9kIGZvciByb3cgZGVuZHJvZ3JhbS4NCiAgICAgICAgI2NvbHVtbl9sYWJlbHMgPSBjb2xuYW1lcyh2c3RfbWF0X3opLCAgICAgICAgICAgICAgICAgICAjVW5jb21tZW50IGZvciBzcGVjaWZ5aW5nIGNvbHVtbiBsYWJlbGluZy4gDQogICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwgICAgICAgICAgICAgICAgICAgI1NldCBmb250IHNpemUgZm9yIGNvbHVtbiBsYWJlbGluZy4NCiAgICAgICAgcm93X2RlbmRfcmVvcmRlciA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBhcHBseSByb3cgZGVuZHJvZ3JhbSByZW9yZGVyaW5nLiANCiAgICAgICAgY29sdW1uX2RlbmRfcmVvcmRlciA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBhcHBseSBjb2x1bW4gZGVuZHJvZ3JhbSByZW9yZGVyaW5nLiANCiAgICAgICAgc2hvd19yb3dfZGVuZCA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBzaG93IHJvdyBkZW5kcm9ncmFtIGNsdXN0ZXJpbmcuDQogICAgICAgIHJvd19kZW5kX3dpZHRoID0gdW5pdCgxMCwgIm1tIiksICAgICAgICAgICAgICAgICAgICAgICAgI1NldCB3aWR0aCBvZiByb3cgZGVuZHJvZ3JhbXMuDQogICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgdG8gc2hvdyBjb2x1bW4gZGVuZHJvZ3JhbSBjbHVzdGVyaW5nLg0KICAgICAgICB3aWR0aCA9IHVuaXQoMiwgImluIiksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgaGVhdG1hcCB3aWR0aC4NCiAgICAgICAgaGVpZ2h0ID0gdW5pdCgxMCwgImluIiksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjU2V0IGhlYXRtYXAgaGVpZ2h0Lg0KICAgICAgICBuYW1lID0gIlotc2NvcmUiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgdGl0bGUuDQojaHQNCiN0aWZmKCIyRF9GdWxsX0hlYXRtYXAudGlmZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImluIiwgcmVzPTYwMCkNCiNkcmF3KGh0KQ0KI2Rldi5vZmYoKQ0KYGBgDQoNCiFbXShUcmVhdGVkLzJEX0Z1bGxfSGVhdG1hcC5zdmcpDQoNCg0KDQo8YnI+DQo8YnI+DQpOZXh0LCBpdCBiZWNvbWVzIGhpZ2hseSB2YWx1YWJsZSB0byB6b29tIGluIG9uICoqc3BlY2lmaWMgZ2VuZSBzdWJzZXRzKiogdGhhdCBhcmUgaW52b2x2ZWQgaW4gcmVsZXZhbnQgKipiaW9sb2dpY2FsIHByb2Nlc3NlcyoqLiBIZXJlaW4sIERFR3MgcmVsYXRlZCB0byAqKmV4dHJhY2VsbHVsYXIgbWF0cml4IG9yZ2FuaXphdGlvbioqLCAqKmdseWNvcHJvdGVpbnMqKiBhbmQgKipzZWNyZXRlZCBmYWN0b3JzKiogYXJlIG1hcHBlZCB0byB1bnZlaWwgdGhlIGltcGFjdCBvZiB0aGUgY2VsbCBzdXJmYWNlIGVuZ2luZWVyaW5nIHByb2Nlc3Mgb24gdGhlIHRyYW5zY3JpcHRvbWUuDQoNCg0KYGBge3IgSGVhdG1hcCBTZWxlY3RlZCBTdWJzZXQgb2YgR2VuZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBmaWcua2VlcD0nYWxsJ30NCiNDcmVhdGUgdmVjdG9ycyBvZiBnZW5lIGxpc3RzDQpHZW5lbGlzdF9FQ00gPSBjKCJBREFNVFMxNSIsICJXTlQxNiIsICJXTlQyIiwgIldOVDlBIiwgIkFOR1BUTDQiLCAiQk1QNCIsICJNTVJOMiIsICJDT0wyMUExIiwgIkNPTDIyQTEiLCAiT01EIiwgIlROWEIiLCAiVEhTRDQiKQ0KR2VuZWxpc3RfR2x5Y29wcm90ZWlucyA9IGMoIkFEQU1UUzE1IiwgIkFQQ0REMUwiLCAiQUJDQTYiLCAiQUJDQTgiLCAiQUJDQTkiLCAiQUJDQjYiLCAiQUJDQzIiLCAiQUJDQzMiLCAiQVRQNlYwRTIiLCAiQlJJTlAxIiwgIkNFQlBCIiwgIkNEMjAwIiwgIkVQSEE1IiwgIkZBTTIwQSIsICJHUFIxMzdCIiwgIkdQUjY4IiwgIkdQUkM1QSIsICJHUFJDNUIiLCAiS0NOSjUtQVMxIiwgIktJVExHIiwgIktJVCIsICJMSUYiLCAiTFlQRDEiLCAiTVBMIiwgIk5PWDQiLCAiU0hBTksyIiwgIlNMSVRSSzQiLCAiU1Q2R0FMTkFDNSIsICJTVDZHQUwyIiwgIkIzR05UOCIsICJXTlQxNiIsICJXTlQyIiwgIldOVDlBIiwgIkFEQ1k0IiwgIkFGUCIsICJNR0FUNEIiLCAiQVJFRyIsICJBTkdQVDEiLCAiQU5HUFRMNCIsICJBR1RSMSIsICJBUVAxIiwgIkFDS1IzIiwgIkIzR0FMVDIiLCAiQjRHQUxOVDEiLCAiQk1QNCIsICJDREgxOCIsICJDREg2IiwgIkNESDgiLCAiQ0hTVDYiLCAiQ0RPTiIsICJDRU1JUCIsICJDSFJNMiIsICJDU0dBTE5BQ1QxIiwgIkNPTDIxQTEiLCAiQ09MMjJBMSIsICJDMVJMIiwgIkNGSFIxIiwgIkNOTk00IiwgIkVOUFA0IiwgIkVMQVBPUjEiLCAiRVNNMSIsICJFRE5SQiIsICJFRk5BNSIsICJFUE9SIiwgIkdSUFIiLCAiR1BDMSIsICJHREYxNSIsICJHREY2IiwgIkhISVAiLCAiSEdGIiwgIkhNTVIiLCAiSFNEMTFCMSIsICJJR1NGMTAiLCAiSUdGQlAzIiwgIklDQU0xIiwgIklGTkUiLCAiSUwxUkwxIiwgIklMMjBSQSIsICJJTDM0IiwgIkpVUCIsICJMUlJOMyIsICJMSVBHIiwgIk1FMSIsICJNWFJBNSIsICJNTVJOMiIsICJORE5GIiwgIk5FVE8yIiwgIk5PVENINCIsICJPTUQiLCAiUExBVCIsICJQREdGUkwiLCAiUExYREMxIiwgIkdBTE5UMTUiLCAiR0FMTlQzIiwgIlBPUERDMyIsICJLQ05LMSIsICJQQ1NLNiIsICJQQ1NLOSIsICJQVEdEUiIsICJQVEdFUjMiLCAiUFRHUzIiLCAiUFRQUlEiLCAiUENESEI1IiwgIlJBRVQxRSIsICJSTkYxMjgiLCAiUk5GMTUwIiwgIlNQUDEiLCAiU0VNQTNDIiwgIlNFTUEzRCIsICJTRU1BNkQiLCAiUFJTUzM1IiwgIlNOQUkxIiwgIlNMQzFBMiIsICJTTEMxMkE5IiwgIlNMQzE0QTEiLCAiU0xDMkExMiIsICJTTEMyQTUiLCAiU0xDMjRBMyIsICJTTEMzOEExIiwgIlNMQzM4QTQiLCAiU0xDNEE4IiwgIlNMQzdBMTEiLCAiU0xDN0ExNCIsICJUTlhCIiwgIlRFTk00IiwgIlRIQkQiLCAiVFJQQzYiLCAiVE1FTTEzMCIsICJWQ0FNMSIpDQpHZW5lbGlzdF9TZWNyZXRlZCA9IGMoIkFEQU1UUzE1IiwgIkFCQ0I2IiwgIkNDTDI2IiwgIkNYQ0wxIiwgIkNYQ0wyIiwgIkNYQ0wzIiwgIkNYQ0w2IiwgIkNYQ0w4IiwgIkMxUVRORjIiLCAiRkFNMjBBIiwgIkhUUkEzIiwgIktDTko1LUFTMSIsICJLSVRMRyIsICJMSUYiLCAiV05UMTYiLCAiV05UMiIsICJXTlQ5QSIsICJBS1IxQjEwIiwgIkFGUCIsICJBTkdQVDEiLCAiQU5HUFRMNCIsICJCTVA0IiwgIkNFTUlQIiwgIkNPTDIxQTEiLCAiQ09MMjJBMSIsICJDMVJMIiwgIkNGSFIxIiwgIkVTTTEiLCAiRUROMSIsICJFUE9SIiwgIkZBQlA1IiwgIkdQQzEiLCAiR0RGMTUiLCAiR0RGNiIsICJISElQIiwgIklHU0YxMCIsICJJR0ZCUDMiLCAiSUZORSIsICJJTDFCIiwgIklMMVJMMSIsICJJTDM0IiwgIkxJUEciLCAiTVhSQTUiLCAiTU1STjIiLCAiTkRORiIsICJPTUQiLCAiUElOTFlQIiwgIlBMQVQiLCAiUERHRlJMIiwgIlBMWERDMSIsICJQQ1NLNiIsICJQQ1NLOSIsICJSQUVUMUUiLCAiU1BQMSIsICJTQ0c1IiwgIlNFTUEzQyIsICJTRU1BM0QiLCAiUFJTUzM1IiwgIlROWEIiLCAiVEhTRDQiKQ0KDQojUmVwbGFjZSBoZXJlIFtHZW5lbGlzdF9FQ01dIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZlY3RvciBmb3Igc3BlY2lmaWMgZ2VuZXMgYygiWFgiLCAiWFkiLCAiWFoiKQ0Kc2VsZWN0ZWRfREVHcyA8LSBHZW5lbGlzdF9TZWNyZXRlZA0KDQojRmlsdGVycyB0aGUgbWF0cml4IHRvIHJldGFpbiBvbmx5IHRoZSByb3dzIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgZ2VuZXMgbGlzdGVkIGluICdzZWxlY3RlZF9ERUdzJyB2ZWN0b3IuDQp2c3RfbWF0U2VsZWN0ZWQgPC0gdnN0X21hdFtyb3duYW1lcyh2c3RfbWF0KSAlaW4lIHNlbGVjdGVkX0RFR3MsIF0NCg0KI0RvdWJsZSBjaGVjayB0byBlbnN1cmUgdGhhdCBhbGwgc2VsZWN0ZWQgREVHcyB3ZXJlIHJldHJpZXZlZA0KI2RpbSh2c3RfbWF0KSAgICAgICAgICAgICAgICAgICAgIzU2OCBERUdzDQojZGltKHZzdF9tYXRTZWxlY3RlZCkgICAgICAgICAgICAjNjAgREVHcw0KI2xlbmd0aChHZW5lbGlzdF9TZWNyZXRlZCkgICAgICAgIzYwIERFR3MNCg0KI0FwcGx5IHJvdyB6LXNjYWxpbmcNCnZzdF9tYXRTZWxlY3RlZF96IDwtIHQoc2NhbGUodCh2c3RfbWF0U2VsZWN0ZWQpKSkNCg0KI0Fzc2lnbiBjb2x1bW4gbmFtZXMgdG8gZWFjaCBzYW1wbGUNCmNvbG5hbWVzKHZzdF9tYXRTZWxlY3RlZF96KSA8LSBjKCIyREMxIiwgIjJEQzIiLCAiMkRDMyIsICIyREM0IiwgIjJEQzUiLCAiMkRHMSIsICIyREcyIiwgIjJERzMiLCAiMkRHNCIsICIyREc1IikNCg0KI0hlYXRtYXAgcGFyYW1ldGVycw0KY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCAgICAgICAgICAgICAgICAgICAgICAgICNDcmVhdGUgc2VnbWVudHMgZm9yIHRoZSBjb2xvciBncmFkaWVudC4NCiAgICAgICAgICAgICAgICAgICAgICBjKCIjMjE2NkFDIiwgIndoaXRlIiwgIiNCMjE4MkIiKSkgICAjQ3JlYXRlIGNvbG9yIGdyYWRpZW50IHdpdGggdGhlIHNwZWNpZmllZCBjb2xvciBjb2Rlcy4NCg0KbGdkX2xpc3QgPC0gbGlzdCh0aXRsZSA9ICJaLXNjb3JlIiwgICAgICAgICAgICAgICAgICAgICAgICNTZXQgbGVnZW5kIHRpdGxlLg0KICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEyKSwgICAgICAgICAgICNTZXQgZm9udCBzaXplIGZvciBsZWdlbmQgdGl0bGUuDQogICAgICAgICAgICAgICAgbGVnZW5kX2hlaWdodCA9IHVuaXQoMi41LCAiY20iKSwgICAgICAgICAgI1NldCBoZWlnaHQgb2YgdGhlIGxlZ2VuZCBib2R5Lg0KICAgICAgICAgICAgICAgIGxlZ2VuZF93aWR0aCA9IHVuaXQoNSwgImNtIiksICAgICAgICAgICAgICNTZXQgd2lkdGggb2YgdGhlIGxlZ2VuZCBib2R5Lg0KICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KDAuNCwgImNtIiksICAgICAgICAgICAgICNTZXQgd2lkdGggb2YgZWFjaCBsZWdlbmQgZ3JpZC4NCiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsICAgICAgICAgICAgICAgICAjV2hldGhlciBzY2FsZSBpcyAnaG9yaXpvbnRhbCcgb3IgJ3ZlcnRpY2FsJw0KICAgICAgICAgICAgICAgIHRpdGxlX3Bvc2l0aW9uID0gInRvcGNlbnRlciIsICAgICAgICAgICAgICNTZXQgcG9zaXRpb24gb2YgdGhlIHRpdGxlLg0KICAgICAgICAgICAgICAgIGdhcCA9IHVuaXQoNCwgIm1tIikpICAgICAgICAgICAgICAgICAgICAgICNTZXQgZ2FwIGJldHdlZW4gaGVhdG1hcCBhbmQgbGVnZW5kLg0KDQoNCmh0X3NlbGVjdGVkIDwtIEhlYXRtYXAodnN0X21hdFNlbGVjdGVkX3osICAgICAgICAgICAgICAgICAjTWF0cml4IGlucHV0IGZvciBoZWF0bWFwLg0KICAgICAgICBjb2wgPSBjb2xfZnVuLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNWZWN0b3Igb2YgY29sb3JzIGZvciBpbnRlcnBvbGF0aW9uLg0KICAgICAgICByZWN0X2dwID0gZ3Bhcihjb2wgPSAiZ3JleTMwIiwgbHdkID0gMC4xNSksICAgICAgICNCb3JkZXIgbGluZSBjb2xvciBhbmQgd2lkdGggb2YgZWFjaCBjZWxsLg0KICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgY29sdW1uIGxhYmVsaW5nLg0KICAgICAgICBzaG93X3Jvd19uYW1lcyA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgcm93IGxhYmVsaW5nLg0KICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksICAgICAgICAgICAgICAgICNTZXQgZm9udCBzaXplIGZvciByb3cgbGFiZWxpbmcuDQogICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29sdW1ucyA9ICJwZWFyc29uIiwgICAgICAgICAgI1NldCBjbHVzdGVyaW5nIG1ldGhvZCBmb3IgY29sdW1uIGRlbmRyb2dyYW0uDQogICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9ICJwZWFyc29uIiwgICAgICAgICAgICAgI1NldCBjbHVzdGVyaW5nIG1ldGhvZCBmb3Igcm93IGRlbmRyb2dyYW0uDQogICAgICAgICNjb2x1bW5fbGFiZWxzID0gY29sbmFtZXModnN0X21hdFNlbGVjdGVkX3opLCAgICAgI1VuY29tbWVudCB0byBzcGVjaWZ5IGNvbHVtbiBsYWJlbGluZy4NCiAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLCAgICAgICAgICAgICAjU2V0IGZvbnQgc2l6ZSBmb3IgY29sdW1uIGxhYmVsaW5nLg0KICAgICAgICByb3dfZGVuZF9yZW9yZGVyID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIGFwcGx5IHJvdyBkZW5kcm9ncmFtIHJlb3JkZXJpbmcuDQogICAgICAgIGNvbHVtbl9kZW5kX3Jlb3JkZXIgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgdG8gYXBwbHkgY29sdW1uIGRlbmRyb2dyYW0gcmVvcmRlcmluZy4gDQogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgdG8gc2hvdyByb3cgZGVuZHJvZ3JhbSBjbHVzdGVyaW5nLg0KICAgICAgICByb3dfZGVuZF93aWR0aCA9IHVuaXQoMTAsICJtbSIpLCAgICAgICAgICAgICAgICAgICNTZXQgd2lkdGggb2Ygcm93IGRlbmRyb2dyYW1zLg0KICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgY29sdW1uIGRlbmRyb2dyYW0gY2x1c3RlcmluZy4NCiAgICAgICAgd2lkdGggPSB1bml0KDMsICJpbiIpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAjU2V0IGhlYXRtYXAgd2lkdGguDQogICAgICAgIGhlaWdodCA9IHVuaXQoMy41LCAiaW4iKSwgICAgICAgICAgICAgICAgICAgICAgICAgI1NldCBoZWF0bWFwIGhlaWdodC4NCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsZ2RfbGlzdCwgICAgICAgICAgICAgICAgICAjUmVmZXJlbmNlIG9iamVjdCBmb3IgbGVnZW5kIHBhcmFtZXRlcnMuDQogICAgICAgICNzaG93X2hlYXRtYXBfbGVnZW5kID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgI1VuY29tbWVudCB0byBoaWRlIGhlYXRtYXAgbGVnZW5kLg0KICAgICAgICBuYW1lID0gIlotc2NvcmUiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgdGl0bGUuDQoNCmh0X3NlbGVjdGVkID0gZHJhdyhodF9zZWxlY3RlZCwgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iKSAjRHJhd3MgaGVhdG1hcCB3aXRoIGxlZ2VuZCBhdCB0aGUgYm90dG9tIHBvc2l0aW9uLg0KDQojT3V0cHV0IHNldHRpbmdzIGZvciBlYWNoIGhlYXRtYXAgKFcgPSB3aWR0aCwgSCA9IGhlaWdodCkNCiMyRF9FQ006IFcgPSAzIHggSCA9IDMuNSB8IE91dHB1dCBzdmc6IFcgPSA1IHggSCA9IDUNCiMyRF9TZWNyZXRlZDogVyA9IDMgeCBIID0gNi41IHwgT3V0cHV0IHN2ZzogVyA9IDQgeCBIID0gNC41DQojMkRfR2x5Y29wcm90ZWluczogVyA9IDMgeCBIID0gMy41IHwgT3V0cHV0IHN2ZzogVyA9IDQgeCBIID0gNC41DQoNCnN2ZyhmaWxlbmFtZSA9ICIyRF9IZWF0bWFwX1NlY3JldGVkLnN2ZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNC41KQ0KZHJhdyhodF9zZWxlY3RlZCwgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iKQ0KZGV2Lm9mZigpDQpgYGANCg0KDQpgYGB7ciByb3dBbm5vdGF0aW9uIHRvIGJlIHVzZWQgd2l0aGluIHJpZ2h0X2Fubm90YXRpb24gbm90IHdvcmtpbmcgeWV0LCBpbmNsdWRlPUZBTFNFfQ0KI2hhID0gcm93QW5ub3RhdGlvbihmb28gPSBhbm5vX21hcmsoYXQgPSBtYXJrX2F0LCBsYWJlbHMgPSBHZW5lc19Eb3VibGVDaGVjaywNCiAgICAgICAgICAgICAgICAgICNsaW5rX3dpZHRoID0gdW5pdCg1LCAibW0iKSwNCiAgICAgICAgICAgICAgICAgICNwYWRkaW5nID0gMC41LA0KIyAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMA0KICAgICAgICAgICAgICAgICAgICAgIywgZm9udGZhY2UgPSAiYm9sZCIgIA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkpDQojaGEgPSByb3dBbm5vdGF0aW9uKGZvbyA9IGFubm9fbWFyayhhdCA9IHdoaWNoKHJvd25hbWVzKHZzdF9tYXRTZWxlY3RlZF96KSAlaW4lIEdlbmVzX0xhYmVsKSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSByb3duYW1lcyh2c3RfbWF0U2VsZWN0ZWRfeilbcm93bmFtZXModnN0X21hdFNlbGVjdGVkX3opJWluJUdlbmVzX0xhYmVsXSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gInJvdyIpKQ0KYGBgDQoNCjxicj4NCkluIGxhcmdlICoqSGVhdG1hcHMqKiwgaW4gb3JkZXIgdG8gYXZvaWQgdmlzdWFsIGNsdXR0ZXJpbmcgYnkgbGFiZWxpbmcgZXZlcnkgZ2VuZSwgaXQgaXMgb2Z0ZW4gdmFsdWFibGUgdG8gbGFiZWwgb25seSBhIHN1YnNldCBvZiBnZW5lcy4NCg0KYGBge3IgSGVhdG1hcCBTcGVjaWZpYyBHZW5lIExhYmVsaW5nLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLmtlZXA9J2xhc3QnfQ0KI0hlYXRtYXAgcGFyYW1ldGVycw0KY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQ3JlYXRlIHNlZ21lbnRzIGZvciB0aGUgY29sb3IgZ3JhZGllbnQuDQogICAgICAgICAgICAgICAgICAgICAgYygiIzIxNjZBQyIsICJ3aGl0ZSIsICIjQjIxODJCIikpICAgICAgICNDcmVhdGUgY29sb3IgZ3JhZGllbnQgd2l0aCB0aGUgc3BlY2lmaWVkIGNvbG9yIGNvZGVzLg0KDQpsZ2RfbGlzdCA8LSBsaXN0KHRpdGxlID0gIlotc2NvcmUiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgbGVnZW5kIHRpdGxlLg0KICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEyKSwgICAgICAgICAgICAgICAjU2V0IGZvbnQgc2l6ZSBmb3IgbGVnZW5kIHRpdGxlLg0KICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDIuNSwgImNtIiksICAgICAgICAgICAgICAjU2V0IGhlaWdodCBvZiB0aGUgbGVnZW5kIGJvZHkuDQogICAgICAgICAgICAgICAgbGVnZW5kX3dpZHRoID0gdW5pdCg1LCAiY20iKSwgICAgICAgICAgICAgICAgICNTZXQgd2lkdGggb2YgdGhlIGxlZ2VuZCBib2R5Lg0KICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KDAuNCwgImNtIiksICAgICAgICAgICAgICAgICAjU2V0IHdpZHRoIG9mIGVhY2ggbGVnZW5kIGdyaWQuDQogICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhvcml6b250YWwiLCAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHNjYWxlIGlzICdob3Jpem9udGFsJyBvciAndmVydGljYWwnDQogICAgICAgICAgICAgICAgdGl0bGVfcG9zaXRpb24gPSAidG9wY2VudGVyIiwgICAgICAgICAgICAgICAgICNTZXQgcG9zaXRpb24gb2YgdGhlIHRpdGxlLg0KICAgICAgICAgICAgICAgIGdhcCA9IHVuaXQoNCwgIm1tIikpICAgICAgICAgICAgICAgICAgICAgICAgICAjU2V0IGdhcCBiZXR3ZWVuIGhlYXRtYXAgYW5kIGxlZ2VuZC4NCg0KDQojQ3JlYXRlIHZlY3RvciB3aXRoIHN1YnNldCBvZiBnZW5lcyB0byBsYWJlbA0KR2x5Y29wcm90ZWluc19zZWxlY3RfbGFiZWwgPSBjKCJBTkdQVDEiLCAiQjNHTlQ4IiwgIk1HQVQ0QiIsICJFRE5SQiIsICJORE5GIiwgIkFEQU1UUzE1IiwgIlNUNkdBTE5BQzUiLCAiQk1QNCIsICJDREg4IiwgIkNPTDIxQTEiLCAiSUwzNCIsICJJQ0FNMSIsICJOT1RDSDQiLCAiT01EIiwgIlNFTUEzRCIsICJWQ0FNMSIpDQpTZWNyZXRlZF9zZWxlY3RfbGFiZWwgPSBjKCJXTlQyIiwgIldOVDE2IiwgIkNYQ0wxIiwgIkNYQ0wyIiwgIkJNUDQiLCAiQ09MMjJBMSIsICJFRE4xIiwgIkdERjYiLCAiSUwxQiIsICJDRU1JUCIsICJMSVBHIiwgIlNDRzUiLCAiTVhSQTUiLCAiSUZORSIsICJTUFAxIiwgIkFOR1BUMSIsICJORE5GIiwgIktJVExHIiwgIkFLUjFCMTAiKQ0KDQojQXNzaWduIGdlbmVzIHN1YnNldCB0byBhIHN0YXRpYyBvYmplY3QgZm9yIGVhc2lseSBzd2l0Y2hpbmcgYmV0d2VlbiBwbG90cw0KR2VuZXNfTGFiZWwgPSBTZWNyZXRlZF9zZWxlY3RfbGFiZWwNCg0KI0lkZW50aWZ5IGluZGljZXMgb2YgdGhlIHJvdyBuYW1lcyBpbiB0aGUgbWF0cml4IHRoYXQgY29ycmVzcG9uZCB0byB0aGUgZ2VuZXMgbGlzdGVkIGluIHRoZSB2ZWN0b3IgJ0dlbmVzX0xhYmVsJyANCm1hcmtfYXQgPSB3aGljaChyb3duYW1lcyh2c3RfbWF0U2VsZWN0ZWRfeikgJWluJSBHZW5lc19MYWJlbCkNCg0KI0V4dHJhY3QgdGhlIHJvdyBuYW1lcyBvZiB0aGUgbWF0cml4IHRoYXQgY29ycmVzcG9uZCB0byBpbmRpY2VzIGluICdtYXJrX2F0Jy4gVGhpcyBzdGVwIGlzIGEgZG91YmxlLWNoZWNrIHRvIGVuc3VyZSB0aGF0IHRoZSBzZWxlY3RlZCByb3dzIGRvIGluZGVlZCBtYXRjaCB0aGUgb3JpZ2luYWwgJ0dlbmVzX0xhYmVsJyB2ZWN0b3IuDQpHZW5lc19Eb3VibGVDaGVjayA8LSByb3duYW1lcyh2c3RfbWF0U2VsZWN0ZWRfeilbbWFya19hdF0NCg0KI0NoZWNrIHdoZXRoZXIgdGhlIHR3byB2ZWN0b3JzIGNvbnRhaW4gdGhlIHNhbWUgZWxlbWVudHMsIHJlZ2FyZGxlc3Mgb2YgdGhlaXIgb3JkZXIuDQpzZXRlcXVhbChHZW5lc19Eb3VibGVDaGVjaywgR2VuZXNfTGFiZWwpICNUUlVFIC0+IHByb2NlZWQgdG8gbGFiZWxpbmcuDQoNCiNOb3RlOiBVc2UgJ0dlbmVzX0RvdWJsZUNoZWNrJyBvYmplY3QgZm9yIGxhYmVsaW5nLCBiZWNhdXNlIGl0IG91dHB1dHMgR2VuZSBzeW1ib2xzIGluIHRoZSBzYW1lIG9yZGVyIGFzICdtYXJrX2F0Jy4gVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSAnbWFya19hdCcgZXh0cmFjdHMgcm93IG5hbWUgbnVtYmVycywgd2hpY2ggYXJlIGF1dG9tYXRpY2FsbHkgb3JkZXJlZCBudW1lcmljYWxseSBpbiB0aGUgb3V0cHV0IHZlY3Rvci4NCg0KIydhbm5vX21hcmsnIGZ1bmN0aW9uIGluIENvbXBsZXhIZWF0bWFwIHBhY2thZ2UgZW5hYmxlcyBsaW5raW5nIGhlYXRtYXAgYW5ub3RhdGlvbiB3aXRoIGN1c3RvbWl6ZWQgbGFiZWxzLg0KZm9vID0gYW5ub19tYXJrKGF0ID0gbWFya19hdCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTnVtZXJpYyBpbmRleCBmcm9tIG9yaWdpbmFsIG1hdHJpeC4NCiAgICAgICAgICAgICAgICAjbGlua193aWR0aCA9IHVuaXQoNSwgIm1tIiksICAgICAgICAgICAgICAgICAgI1VuY29tbWVudCB0byBzcGVjaWZ5IGxhYmVsIGxpbmsgd2lkdGguDQogICAgICAgICAgICAgICAgcGFkZGluZyA9IDAuNzUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNQYWRkaW5nIHNwYWNlIGJldHdlZW4gbmVpZ2hib3JpbmcgbGFiZWxzLg0KICAgICAgICAgICAgICAgIGxhYmVscyA9IEdlbmVzX0RvdWJsZUNoZWNrLCAgICAgICAgICAgICAgICAgICAjQ29ycmVzcG9uZGluZyBsYWJlbHMuDQogICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEwKSwgICAgICAgICAgICAgICNTZXRzIGZvbnQgc2l6ZS4NCiAgICAgICAgICAgICAgICB3aGljaCA9ICJyb3ciKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgJ2NvbHVtbicgb3IgJ3JvdycgYW5ub3RhdGlvbi4NCg0KaHRfc2VsZWN0ZWRfbGFiZWwgPC0gSGVhdG1hcCh2c3RfbWF0U2VsZWN0ZWRfeiwgICAgICAgICAgICAgICAjTWF0cml4IGlucHV0IGZvciBoZWF0bWFwLg0KICAgICAgICAgICAgICAgICBjb2wgPSBjb2xfZnVuLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjVmVjdG9yIG9mIGNvbG9ycyBmb3IgaW50ZXJwb2xhdGlvbi4NCiAgICAgICAgICAgICAgICAgcmVjdF9ncCA9IGdwYXIoY29sID0gImdyZXkzMCIsIGx3ZCA9IDAuMTUpLCAgI0JvcmRlciBsaW5lIGNvbG9yIGFuZCB3aWR0aCBvZiBlYWNoIGNlbGwuDQogICAgICAgICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgY29sdW1uIGxhYmVsaW5nLg0KICAgICAgICAgICAgICAgICBzaG93X3Jvd19uYW1lcyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBzaG93IHJvdyBsYWJlbGluZy4NCiAgICAgICAgICAgICAgICAgI3Jvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA0KSwgICAgICAgICAgI1VuY29tbWVudCB0byBzcGVjaWZ5IHJvdyBsYWJlbCBmb250IHNpemUuDQogICAgICAgICAgICAgICAgICNyb3dfbmFtZXNfc2lkZSA9ICJsZWZ0IiwgICAgICAgICAgICAgICAgICAgICNVbmNvbW1lbnQgdG8gc3BlY2lmeSByb3cgbGFiZWwgc2lkZS4NCiAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2x1bW5zID0gInBlYXJzb24iLCAgICAgI1NldCBjbHVzdGVyaW5nIG1ldGhvZCBmb3IgY29sdW1uIGRlbmRyb2dyYW0uDQogICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9ICJwZWFyc29uIiwgICAgICAgICNTZXQgY2x1c3RlcmluZyBtZXRob2QgZm9yIHJvdyBkZW5kcm9ncmFtLg0KICAgICAgICAgICAgICAgICByb3dfZGVuZF9yZW9yZGVyID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBhcHBseSByb3cgZGVuZHJvZ3JhbSByZW9yZGVyaW5nLg0KICAgICAgICAgICAgICAgICBjb2x1bW5fZGVuZF9yZW9yZGVyID0gVFJVRSwgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBhcHBseSBjb2x1bW4gZGVuZHJvZ3JhbSByZW9yZGVyaW5nLg0KICAgICAgICAgICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBzaG93IHJvdyBkZW5kcm9ncmFtIGNsdXN0ZXJpbmcuDQogICAgICAgICAgICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgY29sdW1uIGRlbmRyb2dyYW0gY2x1c3RlcmluZy4NCiAgICAgICAgICAgICAgICAgd2lkdGggPSB1bml0KDMsICJpbiIpLCAgICAgICAgICAgICAgICAgICAgICAgI1NldCBoZWF0bWFwIHdpZHRoLg0KICAgICAgICAgICAgICAgICBoZWlnaHQgPSB1bml0KDMuNSwgImluIiksICAgICAgICAgICAgICAgICAgICAjU2V0IGhlYXRtYXAgaGVpZ2h0Lg0KICAgICAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxnZF9saXN0LCAgICAgICAgICAgICAjUmVmZXJlbmNlIG9iamVjdCBmb3IgbGVnZW5kIHBhcmFtZXRlcnMuDQogICAgICAgICAgICAgICAgIG5hbWUgPSAiWi1zY29yZSIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgdGl0bGUuDQoNCmh0X21lcmdlID0gaHRfc2VsZWN0ZWRfbGFiZWwgKyByb3dBbm5vdGF0aW9uKG1hcmsgPSBmb28pDQpodF9tZXJnZSA9IGRyYXcoaHRfbWVyZ2UsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgYWxpZ25faGVhdG1hcF9sZWdlbmQgPSAiaGVhdG1hcF9sZWZ0IikgI05vdGU6ICdhbGlnbl9oZWF0bWFwX2xlZ2VuZCcgPSAnaGVhdG1hcF9jZW50ZXInIHBvc2l0aW9uIGlzIG9mZnNldCBiZWNhdXNlIGhlYXRtYXAgaGFzIGJlZW4gbWVyZ2VkIHdpdGggJ3Jvd0Fubm90YXRpb24nLg0Kc3ZnKGZpbGVuYW1lID0gIjJEX0hlYXRtYXBfU2VjcmV0ZWRfQ29tcGFjdExhYmVsLnN2ZyIsIHdpZHRoID0gNC41LCBoZWlnaHQgPSA0LjUpDQpkZXYub2ZmKCkNCmBgYA0KDQoNCg0KDQoNCg==